Banner
Views: 1,003,601,352
Time:
16 users online: Ahrion, AsiagoPizza, Bowsette9999, codfish1002, CogashiGarlic, drkrdnk, Enan63, EvanEMV, Gamma V,  GlitchCat7, gui, JupiHornet, Kimota, mr_cool, Sammmoo, ShadowBoxer_Sandshrew - Guests: 98 - Bots: 232 Users: 54,849 (2,036 active)
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).
Not logged in.
C++ nested and derived classes question
Forum Index - Donut Plains - Computers & Technology - C++ nested and derived classes question
Pages: « 1 » Link
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.

The authors of these 2 My Little Pony fan games have removed their games from the Internet.
Rise of the Clockwork Stallions has been updated! Download My Little Pony: Rise of the Clockwork Stallions DX: Director's Cut and My Little Pony: Magic Shards now! Spread this link!

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.

--------------------
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
O.K., but if I run this code,

Code
#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.

The authors of these 2 My Little Pony fan games have removed their games from the Internet.
Rise of the Clockwork Stallions has been updated! Download My Little Pony: Rise of the Clockwork Stallions DX: Director's Cut and My Little Pony: Magic Shards now! Spread this link!

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:

Code
class One
{
public:
	One(A* myA) : m_myA(myA)
	{
	}

	virtual void output(){cout << m_myA->m_foo << endl;}


private:
	A* m_myA;
}


And then in your A constructor, you could do:

Code
A(){m_o = new One(this);}


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.

--------------------
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
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.

The authors of these 2 My Little Pony fan games have removed their games from the Internet.
Rise of the Clockwork Stallions has been updated! Download My Little Pony: Rise of the Clockwork Stallions DX: Director's Cut and My Little Pony: Magic Shards now! Spread this link!

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.

--------------------
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
So I've changed the code to this,

Code
#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.

The authors of these 2 My Little Pony fan games have removed their games from the Internet.
Rise of the Clockwork Stallions has been updated! Download My Little Pony: Rise of the Clockwork Stallions DX: Director's Cut and My Little Pony: Magic Shards now! Spread this link!

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.

--------------------
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
That worked!

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.

The authors of these 2 My Little Pony fan games have removed their games from the Internet.
Rise of the Clockwork Stallions has been updated! Download My Little Pony: Rise of the Clockwork Stallions DX: Director's Cut and My Little Pony: Magic Shards now! Spread this link!

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".

--------------------
Feel free to visit my website/blog - it's updated rarely, but it looks pretty cool!
Pages: « 1 » Link
Forum Index - Donut Plains - Computers & Technology - C++ nested and derived classes question

The purpose of this site is not to distribute copyrighted material, but to honor one of our favourite games.

Copyright © 2005 - 2022 - SMW Central
Legal Information - Privacy Policy - Link To Us


Menu

Follow Us On

  • YouTube
  • Twitch
  • Twitter

Affiliates

  • Super Mario Bros. X Community
  • ROMhacking.net
  • Mario Fan Games Galaxy
  • sm64romhacks