C++ inheritance: scoping and visibility of members - c++

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!

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.

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.

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.

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)
}
}

Related

clarification of initialization in C++

I am really getting confused in following examples:
#include <iostream>
class C {
public:
int a,b;
};
int main() {
C c{3,6};
std::cout<<c.a<<'\n';
std::cout<<c.b<<'\n';
return 0;
}
It works fine and gives the expected outcome. But if I modify the above code like below.
#include <iostream>
class C {
int a,b;
public:
int get_a(){
return a;
}
int get_b(){
return b;
}
};
int main(){
C c{3,6};
std::cout<<c.get_a()<<'\n';
std::cout<<c.get_b()<<'\n';
return 0;
}
In the above program compiler shows multiple errors. Why uniform initialization allowed in first program but not in second? Where I am wrong?
By default c++ class members are private, so without specifying you get a private variable. Because you made the types private you do not get the aggregate-initialization for free anymore so you need to write your own constructor for this class:
class C{
C(int _a, int _b):
a(_a), b(_b)
{}
};
You just need to fix the namespacing for the cout and your code should compile fine: http://coliru.stacked-crooked.com/a/1d69f4f141d2bcd2
From the standard:
[dcl.init.aggr] An aggregate is an array or a class with no user-provided constructors, no brace-or-equal-initializers for non-static data members, no private or protected non-static data members, no base classes, and no virtual functions
In the first code you only had public variables so the code worked because you had an aggregate, making the variable private is what caused the problem because it was no longer an aggregate according to the above definition.
a and b are private in your second example and are therefore inaccessible from outside the class.
You need to move the line int a,b; into the public: scope like the first example.
You also need std:: in front of cout
#include <iostream>
class C {
public:
int a,b; //Make public
int get_a(){
return a;
}
int get_b(){
return b;
}
};
int main(){
C c{3,6};
std::cout<<c.get_a()<<'\n'; //use namespace std::
std::cout<<c.get_b()<<'\n'; //use namespace std::
return 0;
}
In the modified version of the code, you moved the public: label so the a and b data members are no longer public. Hence, they cannot be referenced from outside the class, even not implicitly by an initializer list.
The first code worked because the data members a and b were public, so they could be accessed from outside the class. However, in the second code, they are declared as private, so they cannot be accessed from outside the class. Either declare them as public again, or use a constructor as follows (if you still want them as private):
C(int x,int y) // This is a parameterised constructor
{
a=x;
b=y;
}
And initialise them as C c(3,6);

Member with the same name of the type

I want to create a member function with the same name of the returning type. Example:
class A { };
class B {
public:
A& A() { return *a; }
private:
A* a;
};
However, the compiler won't let me. I tried to change the type of the member return type to ::A (as sugested here, but with no avail. I know I could just change the member name, but I just want to understand why does it has this restriction, and what are my workarounds.
If you declare a member called A you can no longer use the type A without an explicit namespace. You need to change every occurrence of the type A to ::A.
The corrected code looks like:
class A { };
class B {
public:
::A& A() { return *a; }
private:
::A* a;
};
Fixed code on codepad:
http://codepad.org/cilF9rKm
That's because a member with the same name as the class is a constructor. However, you try to declare one with a type, which is an error. You can only define constructors the way the language wants you too (without an explicit return type).
For example, if you had a method in B that said
A x = A();
it is ambiguous whether you are calling B::A() or are constructing a new A object.

c++ and injected base name

The following code does not compile in gcc:
namespace One{
class A{
};
};
namespace Two{
class A{
public:
void what(){
cout << "Two::A says what!" << endl;
}
};
class B : public One::A{
public:
B(){
A xx;
xx.what();
}
};
};
And it gives:
gccbug.cpp: In constructor ‘Two::B::B()’:
gccbug.cpp:23: error: ‘class One::A’ has no member named ‘what’
Now, I was told that this is correct behavior (due to injected base name of One::A making A refer to One::A). However, this code compiles in C# (well, after changing a few things), so this seems to be c++ specific.
What I'm wondering is.. why? Is there a specific purpose for injecting the base name "One::A" as "A"?
The only reason I can think of is that in C++ you are likely to refer to the base class name in the initializer list of the constructor, like this:
namespace Two {
/*...*/
class B : public One::A {
public:
B():A()
{
/*...*/
}
};
}
Of course the purpose then is different from the one in your example, because you actually declare a local variable inside the constructor, whereas in my example, the A() refers to the object of type A that is implicit in the definition of class B due to inheritance.
However, the situation of my example is more likely to occur, so I guess they thought let's not require the namespace to be made explicit in this case. As a consequence, any reference to A without a namespace is interpreted as referring to the base class, rather than any other class named A, even if it is in the same namespace as the declaration of B.
Is there a specific purpose for injecting the base name "One::A" as "A"?
Yes. It is so that you could write this:
namespace N
{
class A
{
A *a;
};
}
In the absence of injected-name, you've to write N::A *a which is not nice.
Note that it is because of injected-name, the following lines are allowed:
A::A *a1; //ok
A::A::A *a2; //ok
A::A::A::A *a3; //ok
A::A::A::A::A *a4; //ok
//and so on
Online demo
By qualifying A with One:: you added the A from namespace one in scope, so the compiler will look there for it's name resolution.

Syntax for class within a class in C++

If I have the following
class A
{
public:
int stuff;
void helper(B temp, int d); //what about here? I'm getting a 'B' has not been declared error here.
private:
class B
{
public:
int stuffer;
private:
int x;
};
}:
Whats the correct way to refer to class 2 in my implementation file? Would it be
1::2::someMethod? Or 2::someMethod?
Assuming that 1 and 2 refer to REAL class names, 1::2::methodName just like any other nested scoping.
First of all, class name cannot start with integer. So renaming them:
class A
{
public:
int stuff;
private:
class B
{
public:
int stuffer;
private:
int x;
};
};
Second, since the nested class B is in the private section, so you cannot access it from outside the scope of class A. B is accessible to A only. And the syntax of declaring an object of type B would be B bObj; in the scope of A.
Now you should try yourself first, before asking futher questions!
As for your edit (the added question): it's not compiling because by the time the compiler sees B temp, it has not yet seen the definition of B, that is why it says B is not declared!
The fix is very simple. Declare B before it's used, something like this:
class A
{
private:
class B
{
public:
int stuffer;
private:
int x;
};
public:
int stuff;
void helper(B temp, int d);
}; //<--- this is also fixed. your code has 'colon', instead semi-colon!
Also read the comment at the end of the class!
If you're inside a method of class 1, you can use 2::somemethod. In other places, use 1::2::somemethod. "Inside" includes method argument declarations in method implementations of class 1, but not return value declarations for method implementations of class 1.
It depends on which scope level you're at. Inside a member function for class 1, it would be class_2::someMethod. At file scope, it would be class_1::class_2::someMethod. It's always correct to fully qualify a function or variable name like that, but sometimes it's more typing than is strictly necessary. In general, you need the scope resolution operator :: when the compiler can't figure out on its own what you're referring to.
In practice, the best way to find out is try it and see what happens. If the compiler gives you an error, throw the class name in front of it and try again.
Syntax for nested class:
Class class_name1
{
Private:
Data members
Public:
Member functions
{
.........
}
Class class_name2 //class2 is embedded with class1
{
Private:
Data members
Public:
Member functions
{
.........
}
}; // class2
}; //class1
Nested class is possible to define one class within another class since a class declaration does,define a scope.
A nested class is valid only within the scope of the enclosing class.
Need of nested class is virtually not existed.

checking a private variable using a derived class object

below is the small program.
i want to check the value of the private variable x of class A using the object of class B.
is it possible ever?
#include<stdio.h>
#include<conio.h>
#include<iostream>
class A {
int x;
public:
A() {
x=10;
}
};
class B : public A {
public:
int x;
};
int main()
{
B obj;
obj.x=20;
std::cout<< obj.x;
getch();
}
This will output 20, but how can i check the value of x as 10 which is in class A?
i wanted to know whether we can check the value without making x as protected!
You'll have to make the variable protected, or, you can create a protected member method in class A which returns the variable x.
By using the 2nd approach (protected member method or property (is that possible in C++?), class B can read the variable, but cannot change it.
Derived classes cannot see ancestor privates. You can use "protected" for descendents to see the data, but not unrelated classes.
In addition to the private / protected issue, your B::x member over-shades the x of A. So even if both were public, you'd have to write b.A::x. Looks weird, but works (see code below) ....
This is syntax-wise. You should tot do this, of course, as everybody here say. use protected members with meaningful names, and accessor functions
class A {
public:
int x;
};
class B: public A {
public:
int x;
void f() { std::cout << "B::x=" << x << ", A::x=" << A::x << '\n'; }
};
int main()
{
B b;
b.A::x = 10;
b.x = 20;
b.f();
}
output:
B::x=20, A::x=10
You can not examine the value of private members of base class. So: add an accessor in A or make A::x protected.
Make x in A protected and write a method in B that looks something like this:
int getAX(){
return A::x
}
You shouldn't.
Since your A class tells the member is private, nobody but A can access it.
If B is-an-A, the same rule is valid: A::x is still inaccessible.
Your wanting to access it means you either need a different kind of A (i.e. make A::x public), or you want the wrong thing.
Well, if you really want to know if it's possible: it is. public, protected and private are only compile time checks. One possible option to circumvent them during runtime is the following:
#include <iostream>
class A{
int x;
A() : x(10){}
};
struct pubA{
int x;
};
int main(){
A a;
// evil casting
pubA* pa = reinterpret_cast<A*>(&a);
std::cout << pa->x << std::endl; // should print 10
}
That said, don't do it. There is a reason for these keywords. (The above code is untested, 'caus I'm writing from my iPod. If reinterpret_cast doesn't work, use old C-style cast: pa = (pubA*)&a.)