我在派生类中遇到构造函数问题。假设我在下面有一个简单的代码,其中包含一个基类Base和两个继承自Base,Derived1和Derived2的类。
我希望Derived2持有指向Base的指针,它可以指向Base或Derived1。我无法为此编写构造函数。如果我传入Derived1对象,我会在构造函数中获得一个空Base。
Class Base
{
public:
Base(int a): m_a(a)
{
}
protected:
int m_a;
};
//First derived class of base
class Derived1 : public Base
{
public:
Derived1(double c): m_c(c)
{
}
private:
double m_c;
};
//Second derived class of Base
class Derived2 : public Base
{
public:
Derived2(Base b, int k): m_b(&b), m_k(k)
{
}
private:
int m_k;
Base* m_b;
};
int main()
{
Base b(2);
Derived1 d1(3.0);
Derived2 d2(d1, 3);
Derived2 d3(b, 4);
}
答案 0 :(得分:0)
您可能希望在构造函数中接受Base*
,而不是实际的Base
实例:
Derived2(Base* b, int k) : m_b(b), m_k(k)
{
}
然后,您可以传递您希望Derived2
实例指向的实例的地址:
Derived2 d2(&d1, 3);
Derived2 d3(&b, 4);
请注意,您应该考虑Base
实例中指向的Derived2
对象的所有权。此外,如果在删除传递的Derived2
对象后Base
对象仍然存在,则访问m_b
将导致未定义的行为。如果您可以使用C ++ 11,请考虑传递和存储std::shared_ptr<Base>
而不是原始指针。
答案 1 :(得分:0)
我理解您希望Derived2
持有指向另一个Base
对象的指针。
第一个问题:您的构造函数使用基础对象的值参数:
Derived2(Base b, int k): m_b(&b), m_k(k)
这意味着当它被调用时,会为b传递参数的临时副本,并且您将存储此临时对象的地址。当然,一旦你离开调用构造函数的语句,这个地址就会失效。 Segfault迟早会保证!
解决方案: 按引用传递参数(其余代码未更改):
Derived2(Base& b, int k): m_b(&b), m_k(k)
第二个问题:您的代码无法编译,因为Base
没有默认构造函数,Derived1
和Derived2
的构造函数不提供对于初始化列表中的有效Base
。
解决方案1: 在所有派生构造函数中提供显式的基本初始化。例如:
Derived2(Base& b, int k) : m_b(&b), m_k(k), Base(k) // is k the right value ?
{ ... }
解决方案2: 或者考虑使用Base
构造函数参数的默认值:
Base(int a=0): m_a(a) // default parameter is 0
{ ... }
答案 2 :(得分:0)
这里有很多问题。让我们暂时忽略Derived2的设计问题(裸指针是邪恶的)。
专注于Derived1
...
Derived1派生自Base,这意味着是 Base。 Base只有一个参数构造函数(因此没有默认构造函数)
Derived1也有一个1参数构造函数,但是这个参数正在初始化Derived1的数据(m_c
)。
由于Derived 是 Base,因此必须在构建时构建它的Base部分。既然你必须构造Base,而base只有一个1参数的构造函数,你必须在Derived1的构造函数中特别提到它。
像这样:
class Derived1 : public Base
{
public:
Derived1(double c, int some_value_for_base)
: Base(some_value_for_base)
, m_c(c)
{
}
...
};