views:

144

answers:

4

Can you explain why this is not allowed,

#include <stdio.h>

class B {
private:
    int a;
public:
    int a;
};

int main() {
    return 0;
}

while this is?

#include <stdio.h>

class A {
public:
    int a;
};

class B : public A{
private:
    int a;
};

int main() {
    return 0;
}

In both the cases, we have one public and one private variable named a in class B.


edited now!

A: 

The first isn't allowed because it leads to ambiguous definitions. In the 2nd, although you do have both a public and a private a integer variable, you've hidden A::a inside your B class. The compiler knows implicitly what you want because there is a way to explicitly access a hidden variables.

I also believe that it boils down to name mangaling: storage specifiers don't end up as part of the actual name. I could be wrong on this however.

The easiest way to illustrate why one is allowed and why the other isn't is to look at how the compiler would compile a member function that uses each variable.

Inside your class b:

class b {

int a;
public:
int a;

void myMethod()
{
 a = 10; //what a should the compiler use? Ambiguous, so the compiler sez BZZT.
}

}

For the 2nd example:

class A
{
public: 
int a;
}

class B: public A
{
private:
int a;

void someMethod()
{
 a = 10; //implied that you are using B::a (which may be a programmer error)

}

}
Alan
sorry for that. edited now!
Amoeba
+2  A: 

Because B::a hides A::a in the second example. You can still access it, but it needs explicit qualification for the compiler to figure out you are asking for the member of parent class with the same hame.

In the first example both a's are in the same scope, while in the second example the scopes are different.

Nikolai N Fetissov
+15  A: 

In both the cases, we have one public and one private variable named a in class B.

No, thats not true.

In the first case, you can't have two identifiers with the same name in the same scope. While in the second case, B::a hides A::a, and to access A::a you have to fully qualify the name:

b.a = 10; // Error. You can't access a private member.
b.A::a = 10; // OK.
AraK
A: 

Class B in the first example is not valid because C++ cannot distinguish members by their access specifiers (public/private/protected). However, namespaces are a way for C++ to distinguish members. In class B in the second code you don't have a "public a" and a "private a", you have B::a and A::a.

Even if declaring members of the same name/signature with different access specifiers was allowed, there would be no way to address the correct member.

tiftik