我在类层次结构中有两个类,其中父类需要将从它派生的类的实例作为成员变量。举个例子:
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等):
答案 0 :(得分:2)
不考虑编码问题,从概念的角度来看,这些陈述是否真的有意义? 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();}