Home > OS >  Defining a nested class out of line in C
Defining a nested class out of line in C

Time:02-04

Sorry if this has been asked before; I found similarly titled questions, but none of them focused on the same aspects I'm having trouble with.

There's a class A, and a class B that should only be accessible from A. I think nesting B inside A will achieve that, but I'm struggling with the logistics.

A has a B as a member. As such, not defining B prior to declaring A's members causes incomplete type errors. I thought I'd get around this by declaring A, defining A::B, then defining A, but that just throws the same errors plus incomplete type 'A' in nested name specifier.

class A;

class A::B
{
    ...
};

class A
{
private:
    class B;
    B b;
    ...
};

The only functional examples I can find would put B's member declaration directly inside A's, which I'd really like to avoid doing: B's header information is several times longer and much denser than A's. Splitting the two up into separate files would be best, but actually nesting them inline is incredibly unwieldy.

Fallback options at this point include making A's B a pointer (no real reason why not, but is this really something that can't be done?) and leaving them as independent classes. But surely this can't be that hard?

What do I need to declare to link these properly and in what order?

I am not particularly knowledgeable about the depths of C so please explain like I'm five and refrain from shaming me into the ground for not knowing everything.

CodePudding user response:

Since b is a non-reference non static data member of class A, it must be declared to have a complete type.

One way to solve this would be to either make b a reference type(as shown below) or a pointer to a B:

class A
{
private:
    class B;
//--vv------------>now b is an lvalue reference to a B object
    B& b;   
};


class A::B
{
    
};

Method 2

Other option is to define B inside A with only its member declaration and then define those members outside as shown below:


class A
{
private:
    //defined class now 
    class B
    {
         void member1();
    };

    B b;      //works now 
};

void A::B::member1()
{

}

CodePudding user response:

The only functional examples I can find would put B's member declaration directly inside A's, which I'd really like to avoid doing: B's header information is several times longer and much denser than A's. Splitting the two up into separate files would be best, but actually nesting them inline is incredibly unwieldy.

The premise is interesting until I saw this comment of yours, I assume by you mean "Hide" is "Hide the Code it Self", not the members and method of B?

B is already tailored to the specifics of A and wouldn't be reusable without modification. That's really why I want to hide it.

And with this line, can I assume that you aren't familiar with the concept of inheritance?

I am not particularly knowledgeable about the depths of C so please explain like I'm five and refrain from shaming me into the ground for not knowing everything.

You can simply inherit Class A into Class B, then use Class B itself? or the other way around. Just remember that the Base Class [Class A in this Case] has no idea what methods or member the Derived Class has [Class B in this Case].

e.g.All (Derived)Airplanes can (Base)Fly but not everything that can Fly is an airplane.

A Little Introduction to Inheritance can be found here. and if you do decide to go through this route, please Read up on a lot of materials about it. It's a Deep hole.

class A
{
public:
    A()
    {
        x=0;
        y=0;
        std::cout << "A's Default Constructor Used " << std::endl;
    }
    virtual ~A(){std::cout<<"A's Destructor called" << std::endl;};
    int x;
    int y;
};
class B : public A
{
public:
    B(){}
    B(int nX, int nY){x=nX,y=nY;}
    ~B(){std::cout<<"B's Destructor Called"<<std::endl;}
public:
    void SomeMethod(int nX){x =nX;}
};

int main() {

    B b;
    std::cout << b.x << " " << b.y << std::endl;
    b.SomeMethod(10);
    std::cout << b.x << " " << b.y << std::endl;

}

NOTE: On A's destructor [virtual ~A(){std::cout<<"A's Destructor called" << std::endl;};] the keyword virtual is not needed unless you are deleting / destroying Class B from a Pointer to an Object of Class A, and Absolutely necessary if you are, Like Below.

B* b = new B;
std::cout << b->x << " " << b->y << std::endl;
b->SomeMethod(10);
std::cout << b->x << " " << b->y << std::endl;
A* a = b;
delete a;

Without the virtual keyword, only A's Destructor would be called and not B's.

Unless inheritance is out of the question then Nesting(Which I personally don't recommend it's a big pain on maintenance) ,creating a pointer of Class B inside A. Or simply create Class B inside Class A like below.

class B
{
public:
    B()
    {
        z = 0;
        std::cout<<"B Default Constructor Used"<<std::endl;
    }
    B(int nZ)
    {
        z = nZ;
        std::cout<<"B Constructed"<<std::endl;
    }
    ~B(){}
public:
    void SomeMethod(int& nX,int nY){nX  = ( nY   z );}
    int z;
};
class A
{
public:
    A()
    {
        x=0;
        y=0;
        std::cout << "A Default constructor used" << std::endl;
    }
    
    A(int nX,int nY,int nZ)
    {
        x = nX;
        y = nY;
        b.z = nZ;
        std::cout << "A's Constructed" << std::endl;
    }
    ~A(){};
    B b;
    int x;
    int y;
};


int main() {
    A a;
    a.b.SomeMethod(a.x,10);
    std::cout << a.x << std::endl << std::endl;
    // Ore something like this;
    A a2 = A(1,2,3);
    a2.b.SomeMethod(a2.x,20);
    std::cout << a2.x << std::endl;
}

Just remember to create a Default Constructor for Class B since it would be called during the creation of Class B. Take note that I am speaking from my personal Experience and Knowledge, and by no means is it gospel, specially when I am self taught, and Using conventions that I am using in my own projects.

  • Related