YO-YO PROBLEM WITH C++

Occasionally a new developer may need to work in an existing object oriented program. Generally most developers use more traditional block structured programming techniques so inheritance is sparingly used.

There have been cases where inheritance has been used very heavily which makes it difficult to follow.

class a : public b { /* ... */ }

Is the usual syntax for inheritance with C++ when a wants to inherit b’s data and methods. The idea of inheritance is code reuse.

Libraries of code are popular and using the C++ namespace is an easier idea to compartmentalize functions.

The Yo-Yo problem arises when somebody uses inheritance excessively. This is rare with C++ in open source packages we have examined.

struct person {
    std::string surname;
    std::string forename;
    std::bool male;
}

Now that we have a class for a person we can add a data class

struct date {
     std::int m, d, y;
}

With a data we can now create a citizen

struct citizen : public person {
    std::string nationality;
    date born;
    std::bool naturalized;
}

Careful class design with proper flow and logic can make C++ classes very powerful for abstract design principles. In practice most data is stored in simple SQL databases which handle most types of data easy enough.,

Notice in the example that the date class is not inherited but rather is used as a container in another class which is another common strategy. Notice as well that struct is by default public while a class is private by default.

Now being more cautious with class designs, we avoid the yo-yo problem and diamond problem with careful consideration of what is really needed.

Best practice is to make a chart with the class design in Visio or some other tool so that the code compilation errors are easier to fix. Biggest problem is ambiguity over function calls when classes use the same names etc. Remember you cannot use a base class more than once or you will get an error.

To use a base class twice you may need to use indirect classes:

class L { /* ... */ };                  // indirect base class
class B2 : public L { /* ... */ };
class B3 : public L { /* ... */ };
class D : public B2, public B3 { /* ... */ }; // valid use

Remember that documented class charts make it easier to avoid the yo-yo headache. B2::L and B3::L are qualified function which mitigate compiler errors and get multiple copies of L

As a matter of style we prefer to use fully qualified calls to prevent name clashes.