在C++中定义嵌套类

pbossiut  于 2023-02-06  发布在  其他
关注(0)|答案(3)|浏览(133)

抱歉,如果之前有人问过这个问题;我找到了标题相似的问题,但没有一个关注的是我遇到麻烦的那些方面。
有一个类A和一个只能从A访问的类B。我认为将B嵌套在A中可以实现这一点,但我在逻辑上很挣扎。
A有一个B作为成员。因此,在声明A的成员之前不定义B会导致不完整类型错误。我想我可以通过声明A,定义A::B,然后定义A来解决这个问题,但这只会抛出相同的错误加上incomplete type 'A' in nested name specifier

class A;

class A::B
{
    ...
};

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

我能找到的唯一的函数式示例是将B的成员声明直接 * 放在 * A的内部,我真的希望避免这样做:B的头信息比A的头信息长几倍,密度也大得多。将两者拆分成单独的文件是最好的,但实际上内联嵌套它们是非常笨拙的。
在这一点上,后备选项包括使A的B成为一个指针(没有真实的的理由为什么不这样做,但这真的是不能做到的吗?),并使它们成为独立的类。
我需要声明什么才能正确地链接这些内容以及它们的顺序是什么?

我不是特别了解C++的深度,所以请像我五岁一样解释,不要因为我什么都不知道而羞辱我。

mrphzbgm

mrphzbgm1#

由于b是类A非引用非静态数据成员,因此必须声明它具有完整类型。
解决这个问题的一种方法是将b设置为引用类型(如下所示)或指向B的指针:

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

class A::B
{
    
};
方法2

另一种选择是在A内部定义B,仅使用其成员声明,然后在外部定义这些成员,如下所示:

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

    B b;      //works now 
};

void A::B::member1()
{

}
vlurs2pr

vlurs2pr2#

一个特别简单的方法是

class B
{
   friend class A;
   private:
    // everything;
};

class A
{
  B b;
};

这当然使得B的所有内部都可以被A访问,如果B是A特有的,这应该不是问题。
如果不希望这样做,则可以采用稍微磨损的风路径来解决问题

class PreA
{
   protected:
      class B { ... };
};

class A : PreA
{
   B b;
};
lsmepo6l

lsmepo6l3#

我能找到的唯一的函数式示例是将B的成员声明直接放在A的内部,我真的希望避免这样做:B的头信息比A的头信息长几倍,密度也大得多。将两者拆分成单独的文件是最好的,但实际上内联嵌套它们是非常笨拙的。
前提是有趣的,直到我看到你的这个评论,我假设你的意思是"隐藏"是"隐藏代码它自己",而不是b的成员和方法?
B已经根据A的具体情况进行了定制,如果不进行修改就无法重用,这就是我想要隐藏它的真正原因。
对于这行代码,我可以假设您不熟悉继承的概念吗?
我不是特别了解C++的深度,所以请像我五岁一样解释,不要因为我什么都不懂而羞辱我。
您可以简单地将类A继承到类B中,然后使用类B本身--或者相反。只要记住基类 [在本例中为类A] 不知道派生类 [在本例中为类B] 具有什么方法或成员。
例如,* 所有(衍生)飞机都可以(基本)飞行,但不是所有可以飞行的飞机都是飞机 *。
如果你真的决定走这条路,请阅读大量关于它的资料,这是一个很深的洞。

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;

}
    • 注意:**在A的析构函数[virtual ~A(){std::cout<<"A's Destructor called" << std::endl;};]上,除非你要从指向类A的对象的指针中删除/销毁类B,否则不需要关键字virtual,并且如果你是这样的话,绝对需要,如下所示。
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;

如果没有virtual关键字,则只会调用A的析构函数,而不会调用B的析构函数。
除非继承是不可能的,那么嵌套(我个人不推荐,这是一个很大的维护痛苦),在A中创建一个类B的指针。或者简单地在类A中创建类B,如下所示。

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

只要记住为类B创建一个默认构造函数,因为它会在创建类B的过程中被调用。请注意,我是从我个人的经验和知识说的,这绝不是福音,特别是当我是自学成才的,并使用我在自己的项目中使用的约定时。
声明一个类为static也是防止类B的创建的一种方法,但是可以使用它的函数。但是我很少发现在生产中需要这样做。我主要是在调试中使用它。因为我只在C#中看到过它的使用,而且我从来没有尝试过在生产中使用它,因为我不知道它会产生什么样的行为。

#include <iostream>
static struct B
{
protected:
        B(){};
public:
    static void PrintSomething(int x)
    {
        std::cout <<"Printing Something " << x <<std::endl;
    }
    static void MultiplyBy2(int* x)
    {
        int Two = 2;
        *x = *x * Two;
    }
};
class A
{
public:
    A(int nX,int nY):X(nX),Y(nY){}
public:
    int GetX()const{return X;}
    int GetY()const{return Y;}
    int* PointerToX() {return &X;}
private:
    int X;
    int Y;
};

int main()
{
    A a(1,2);
    B::PrintSomething(a.GetX());
    B::MultiplyBy2(a.PointerToX());
    B::PrintSomething(a.GetX());
    B::MultiplyBy2(a.PointerToX());
    B::PrintSomething(a.GetX());
    return 0;
}

相关问题