Why can the derived class have the same data members from the base class?

848 views Asked by At

As having same data members in both base and derived classes, it creates a lot of confusion and requires usage of the scope resolution operator to resolve conflicts. So why is it allowed in C++? Can anyone show me the need for this?

3

There are 3 answers

3
David Rodríguez - dribeas On

In a sensible design, this should never be an issue. If you are knowingly creating members with the same name as your bases, it is your design that has an issue. If you unknowingly do it, you will not notice.

On the other hand, if this was forbidden at the language level, they the unknowingly part would become a hard error. Consider the use of a framework from which you inherit. Now consider that there is public interface that is well documented, but anything that is private is undocumented. Now you need to inherit from a type (say a Window) and you have this variable with a beautiful meaningful name that makes all the sense in the world. You add that to your type, run the compiler only to find out that the name was already used in the base type (or somewhere up in the hierarchy)...

3
Vivian Miranda On

Overshadowing is not always bad. One counterexample where shadowing is very important is when we work with variadic templates (especially tuples)

Example : Consider the following oversimplified implementation of a tuple. This was the first example I saw how to use variadic templates.

template<typename... T> class tuple0;

template<> class tuple0<> {}; // end recursion

template<typename Head, typename... Tail>
 class tuple0<Head, Tail...> : public tuple0<Tail...> {
 public:
 Head head;
};

Suppose now we want to create tuple0<int, double> and access both elements. Here is a test program that does that

int main()
{    
    tuple0<int, double>* t1  = new tuple0<int, double>;
    t1->head = 7; //  set the integer value
    std::cout << "integer: " << t1->head << std::endl; 
    tuple0<double>* t2 = static_cast< tuple0<double>* >(t1);
    t2->head = std::cos(2);  // set the double value
    std::cout <<  "double: " << t2->head << std::endl;
    return 0;
}

Here you can see that without overshadowing, it would be much harder to work with variadic templates. In addition, the get<> method in std::tuple has a similar implementation.

1
Marcin Łoś On

I don't know the precise motivation, but I believe it's a simple extension of few similar cases, where it is inevitable. Consider for example multiple inheritance - many base classes may have the same members, and there is basically nothing you can do about it as the derived class' creator. Even worse for CRTP - you cannot possibly know members of the base class, since it is arbitrary. These cases seem less confusing than the subject of your question, and are much more problematic, as they cannot be simply forbidden without crippling some features. Since the ambiguity problem must be tackled anyway, it seems only natural that this particular case is handled with the same uniform rules.