父类中的子类的实例

时间:2010-11-26 23:09:36

标签: c++ oop parent-child relationship

我在类层次结构中有两个类,其中父类需要将从它派生的类的实例作为成员变量。举个例子:

class B;

class A {
public:
    B* binst;

    A();
};

class B : public A {
};

A::A() {
    binst = new B;
}

显然,这会导致构造函数中的无限递归,因为要创建一个新的B,你必须调用A的构造函数,这会创建一个新的B来调用A的构造函数,因此无限制地使用。

有解决方法吗?我遇到的问题是A必须有一个B,但B必须从A派生,而且没有办法阻止它。

要了解我为什么需要这样做,请考虑脚本语言的面向对象层次结构(如python或ruby或lua等):

  1. 任何事物的所有实例都是从基类Object派生的。
  2. Object有一个方法查找表,它是MethodTable的一个实例。
  3. MethodTable派生自Object,必须是脚本语言才能对其进行操作。

8 个答案:

答案 0 :(得分:2)

  • “对象有一个方法查找表”
  • “MethodTable派生自Object”

不考虑编码问题,从概念的角度来看,这些陈述是否真的有意义? MethodTable应该有自己的MethodTable,然后有自己的MethodTable ......等等吗?

我说这听起来像你需要重构一下你的概念。例如,也许Object本身应该以某种方式负责公开其MethodTable成员的必要部分。因此,不要求MethodTable本身成为Object。 (也可能有其他各种可行的设计。如果不深入了解实际项目,很难说。)

答案 1 :(得分:0)

编辑:通常,编译器/实现内部类型不是从依赖于语言的类型派生的。如果你看一下Java的内部结构,它们的继承实现将不会派生自Object。对象是一种语言结构,它是语言界面的一部分。方法表是实现的一部分。方法表不应该由语言操作,它应该由实现操作。

此外,强制派生自Object是一件愚蠢的事情,因为你没有考虑语言设计以及用户如何正确编写通用代码。这在动态类型语言(如Lua或Python)中尤其为真。

答案 2 :(得分:0)

通过这种结构确切地了解你将会有所帮助。

正如您已经注意到的那样,这实际上就像让A的构造函数构造A的实例,这是堆栈溢出的不可避免的路径。

更通用的解决方案是为指向A实例的指针提供set_subclass方法,然后可以由A的任何子类填充,而不仅仅是B.

class A {
public:
    A();
    virtual ~A();

    set_subclass(A* sub) { subclass = sub; }
private:
    A* subclass;
};

答案 3 :(得分:0)

你可以为A类创建一个构造函数,它接受一个指向B类对象的指针,并分配这个指针,而不是分配一个新的B:

A::A(B* b) : binst (b) {}

在B类的构造中,你在A:

的构造函数中传递'this'
B::B() : A(this) {} 

编译器可能会抱怨它,但你可以试试。 (虽然很难看。)

请注意,您不能使用binst指针访问A的构造函数中的对象B,因为它尚未完全构造。

答案 4 :(得分:0)

Object可以有一个私有的MethodTableImpl成员和一个返回MethodTable的公共getter。 MethodTable包含一个MethodTableImpl并派生自Object。

答案 5 :(得分:0)

我不知道你班级的目的,但这是一个建议:

class A
{
public:
    virtual void func DoIt () = 0;
    ...
};

class B : public virtual A
{
public:
};

class C : public virtual A ,B
{
    void func DoIt () { /* statements */ }
};

现在只有一个A类实例。

答案 6 :(得分:0)

// List(1) or Stream(2) using inheritance
struct B;

struct A { 
  B *inst; 
  A(B *inst_) : inst(inst_) {}
  A()  : inst(0) {}
};

struct B : A {
  B(B *_inst) : A(inst) {}
  // chose option 1 or 2
  B() : A() {}       // option 1: List
  B() : A(0) {}      // same as above
  B() : A(this) {}   // option 2: Stream
};

auto B3 = new B(new B( new B));
// This is either a length 3 list (1)
// or a stream (2) implemented by self ref 3rd element

答案 7 :(得分:0)

它确实需要binst作为成员,还是只需要访问它?

class B;

class A {
public:
    B& binst(); //throws exception if not derived from B

    A() {}
    virtual ~A() {} //effectively required for the dynamic_cast
    void foo();
};

class B : public A {
public:
    void bar() {};
};

B& A::binst() {return dynamic_cast<B&>(this);} 
void A::foo() {return binst().bar();}