Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nested class inherits from nested class

I wanted the class C inherits from class A its virtual functions, and class D(nested class in class C) inherits from class B(nested class in class A) its data fields, here is what I have.

file1.h

class A{
 public:
     virtual void foo()=0;
     class B{
       public:
         int data;
     };
};

file2.h

class C : public A{
 public:
     class D : public A::B{

     };    
};

file2.cpp

void C::foo(){//code}
C::D::D():data(0){//Bad initialization list, error being data is not a member of C::D even it should inherits from its base class
 data = 0; //good! compiler can see data is a member of A::B,and C::D inherits from it
}

I got two questions, first one is that is what I am doing the correct way to achieve this kind of inheritance. Secondly, as I commented, why compiler can see data is from A::B in the manual initialization process but not in the initialization list? Shouldn't them be in the same scope? Thank you very much

Edit1:

So if class C::D(foo) doesn't directly inherits from A::B(foo), but C inherits from A, my perception is that since C inherits from A and all its public fields, including its inner class A::B(foo), D(foo) has the exactly same name as A::B(foo) and is an inner class of C, like this, i.e used foo for both inner classes

class A{
 public:
     class foo{
       public:
         int data;
     };
};

class C : public A{
 public:
     class foo{

     };    
};

Would it be confusing for the compiler when I call the C::foo directly? since there are two constructors with the name in the scope? or it chooses to call the "nearest" one, e.g C:foo? instead of climbing up the inheritance chain? Thank you very much

like image 564
Cong Hui Avatar asked Feb 19 '23 03:02

Cong Hui


2 Answers

  1. Yes, your approach is the correct way to achieve this kind of inheritance.

  2. Initializer lists are there to control the arguments passed to the constructor. You can pass arguments to B's constructor, but not directly initialize a member of B (it's the job of its constructor). If there is no constructor specified for a base class or a member, the default constructor is used. In your case, add a constructor to B to achieve what you want.

    class A {
    public:
        class B{
        public:
            B(int i) : data(i) {}
            int data;
        };
    }; 
    
    class C : public A {
        class D : public A::B {
        };
    };
    
    C::D::D() :B(0) { }
    
like image 123
AProgrammer Avatar answered Feb 27 '23 05:02

AProgrammer


From a syntactical point of view, it's correct(*1). Apart, of course, from the initialization list. You can only initialize current-class members (not base-class members) in the initializer list. That has nothing to do with the nesting.

class X
{
public: 
   int x;
};
class Y : X
{
   Y() : x(0) {} //still illegal
};

I said syntactical POV because it's a weird thing to do... I'm sure there's a cleaner way to achieve what you actually want.

like image 43
Luchian Grigore Avatar answered Feb 27 '23 04:02

Luchian Grigore