Tip: Ask the author for permission before extracting any resources, such as graphics, music, or ASM from a hack or other non-public source (such as SPC files).
Let's say I defined a class called A and put another class called One inside of A. Let's say I make another class called B that's derived from A. Does B inherit the One class which I can then derive?
Code
class A
{
public:
class One
{
public:
// functions
protected:
// variables
};
protected:
// variables
};
class B : public A
{
public:
class Two : public One
{
public:
// functions
protected:
// variables
};
protected:
// variables
};
If so, then let's say I add the following code. Is the Two class inside C a completely different class than the one inside B or will the compiler complain about the fact that there are 2 classes with the same name?
Code
class C : public A
{
public:
class Two : public One
{
public:
// functions
protected:
// variables
};
protected:
// variables
};
Click the character on the right side of my layout to visit my Discord server and discuss and play and look at and get updates and sneak peeks of the games and other things I'm making.
For the first question: yes, class B can see class One when inherting from A. Just verified this by running the code through an online compiler.
For the second question: yes, both Two classes are completely separate ones. They aren't related to one another at all, aside from inherting the same base class. When putting a class inside a nother class, it basically works the same as a name space, so what the compiler really creates are the classes "B::Two" and "C::Two", therefore there's no conflict.
Apparently, the compiler won't even complain when you make C inherit from B. I'm assuming in that case the Two definition in C will shadow the Two definition in B. However, it's best to avoid scenarios like that, as ambiguities like that will always lead to problems further down the line where you will suddenly find your code using a different class from what you expected or something like that.
#include <iostream>
using namespace std;
class A
{
public:
class One
{
public:
virtual void output(){cout << m_foo << endl;}
protected:
// variables
};
A(){m_o = new One;}
~A(){delete m_o; m_o = nullptr;}
virtual void output (){m_o->output();}
protected:
int m_foo{1};
One* m_o{nullptr};
};
class B : public A
{
public:
class Two : public One
{
public:
// functions
protected:
// variables
};
B(){m_o = new Two;}
protected:
// variables
};
int main()
{
A* z{new B};
z->output();
delete z;
z = nullptr;
return 0;
}
I get this error. What's wrong?
Code
main.cpp: In member function ‘virtual void A::One::output()’:
main.cpp:10:39: error: invalid use of non-static data member ‘A::m_foo’
virtual void output(){cout << m_foo << endl;}
^~~~~
main.cpp:21:16: note: declared here
int m_foo{1};
^
Click the character on the right side of my layout to visit my Discord server and discuss and play and look at and get updates and sneak peeks of the games and other things I'm making.
Nested classes don't know anything about the classes they're contained in. It's basically as I said: when you nest clasess, it acts just like a namespace. It only affects the names of your class, but nothing else. So in your case, because One is declared inside A, the classes full name becomes A::One - but that's all. One doesn't know anything about A, and A doesn't know anything about One. They're two entirely separate classes. This means One can't see the m_foo that is defined in A.
If you want One to access variables in A, you would have to pass a pointer to an A instance to your One class, like so:
Note that this still likely won't work out of the box, because m_foo is protected in A, so One doesn't have access to it, as far as I know. This means to do this, you'd either have to make A a friend class of One, or you'd have to add a public getter function for m_foo to A.
But I thought I read somewhere that C++11 changed the rules so that One DOES know about A. Am I mistaken?
Click the character on the right side of my layout to visit my Discord server and discuss and play and look at and get updates and sneak peeks of the games and other things I'm making.
I'm guessing this doesn't mean what you think it does. I assume that One knowing about A just means that One can see the symbols within A (probably including private ones? Not sure). A and One are still seperate classes. This means that instances of A and instances of One are also separate. An instance of One has no way of knowing whether it's actually a member variable with an A class or something else entirely, therefore One can't access any contents of A without getting an actual pointer to A passed in.
#include <iostream>
using namespace std;
class A
{
public:
class One
{
public:
One(A* a) : m_a(a){}
virtual void output(){cout << m_a->get_foo() << endl;}
protected:
A* m_a{nullptr};
};
A(){m_o = new One(this);}
virtual ~A(){delete m_o; m_o = nullptr;}
virtual int get_foo(){return m_foo;}
virtual void output (){m_o->output();}
protected:
int m_foo{1};
One* m_o{nullptr};
};
class B : public A
{
public:
class Two : public One
{
public:
Two(A* a) : m_a(a){}
virtual void output(){cout << m_a->get_foo() + 1 << endl;}
protected:
// variables
};
B(){m_o = new Two(this);}
protected:
// variables
};
int main()
{
A* z{new B};
z->output();
delete z;
z = nullptr;
return 0;
}
and I'm getting these errors.
Code
main.cpp: In constructor ‘B::Two::Two(A*)’:
main.cpp:33:21: error: class ‘B::Two’ does not have any field named ‘m_a’
Two(A* a) : m_a(a){}
^~~
main.cpp:33:26: error: no matching function for call to ‘A::One::One()’
Two(A* a) : m_a(a){}
^
main.cpp:10:9: note: candidate: A::One::One(A*)
One(A* a) : m_a(a){}
^~~
main.cpp:10:9: note: candidate expects 1 argument, 0 provided
main.cpp:7:11: note: candidate: constexpr A::One::One(const A::One&)
class One
^~~
main.cpp:7:11: note: candidate expects 1 argument, 0 provided
main.cpp:7:11: note: candidate: constexpr A::One::One(A::One&&)
main.cpp:7:11: note: candidate expects 1 argument, 0 provided
What? Why is it saying that Two doesn't have any field named m_a? m_a should have been inherited from One, right? And why is Two's constructor trying to call One's constructor?
Click the character on the right side of my layout to visit my Discord server and discuss and play and look at and get updates and sneak peeks of the games and other things I'm making.
I'm not entirely sure, but I think that's just a limitation of initializer lists. I think they can only access members that were declared in the class itself, not members that were declared in the parent class. If you rewrite the constructor like this:
Code
Two(A* a) : One(a) {m_a = a;}
It will compile. In fact, in this case, the assignment isn't even needed, becuase the One constructor is explicitly called. So it could be simplified to:
Code
Two(A* a) : One(a) {}
As for your last question, I'm not sure, but I'm guessing if no constructor of the parent class is explicitly specified, C++ automatically tries to call one? I'm guessing it automatically tries to call the default construcotr (a constructor without any parameters), which doesn't exist in this case, so I'm guessing that's what's causing the error. I assume calling a parent constructor is simply something the language requires (and not doing so seems like a bad idea, anyways, since if anything changes about the parent class, you might be missing some vital initialization steps). Simply calling a constructor explicitly like in my example is usually the best idea.
However, now I'm having another problem. If I add a int m_foo{3}; to the protected section of B, I would expect the output to be 4, but, for some bizarre reason, it's not. The output is 2, which suggests that get_foo() is returning A's foo then B's Output() function is outputting that + 1. But that doesn't make any sense! B redefined m_foo and initialized it to 3, so the get_foo() function that B inherited from A should return 3, then 1 should be getting added in B's overridden output() function causing 4 to be output. What's going on here?
Click the character on the right side of my layout to visit my Discord server and discuss and play and look at and get updates and sneak peeks of the games and other things I'm making.
It actually makes perfect sense. Redefining a variable doesn't replace that variable. It only creates a new variable with the same name. This is called "shadowing", because the new variable actually "hides" the old variable. When you define a variable m_foo in B, that is an entirely new m_foo and different from the m_foo in A. Since the output() function that prints m_foo is A, the m_foo in A is also what is printed. There's two ways of fixing this that I can think of:
a) Override the output() function in B and make it print m_foo. That should print the m_foo that is actually sitting in B instead of the one that is sitting in A.
b) The better solution: remove the definition of m_foo from B and instead set m_foo to 3 in B's constructor. That will corectly modify the m_foo variable that is inside A.
Shadowing can be useful sometimes, but it's usually best to avoid it, since it introduces ambiguities and makes code harder to read. In the case of inheritance in particular, I don't think shadowing is ever a good idea, since it can easily introduce a bunch of subtle bugs because you no longer know which variable is being accessed (the one from the child class or the one from the parent class). In fact, I'm kinda surprised C++ allows this in the first place. This is probably just another side effect of C++ being so old. I'm pretty sure all C++ compilers at least have warnings for this (although they might be opt-in warnings that have to be enabled first). Usually the warning would read something like "variable 'int m_foo' declared in class B hides variable 'int m_foo' declared in class A".
Follow Us On