0

在以下情况下,拥有一个成员并将其传递给基类可以工作:

DerrivedClass::DerrivedClass(SomeParamType* p)
    : BaseClass(p),
      derrivedClassMember(p),
{
 ...
}

...但是如何在不将其作为参数传递给 DerivedClass 构造函数的情况下进行共享?这是有效的吗?还是此时没有初始化derrivedClassMember?

DerrivedClass::DerrivedClass()
    : BaseClass(derrivedClassMember),
      derrivedClassMember(new SomeParamType()),
{
 ...
}

我无法更改基类实现。

4

5 回答 5

4

在 C++11 中,您可以使用委托构造函数:

class Derived : public Base {
public:
    Derived() : Derived(new SomeParamType()) {}
    ...
private:
    Derived(SomeParamType* p) : Base(p), derivedMember(p) {}
};

作为旁注,我知道这可能只是一个示例,但您不应该在构造函数中像这样在堆上创建非托管对象:如果Base构造函数抛出,那么您将陷入内存泄漏。尽可能使用智能指针。

于 2013-09-05T08:57:33.867 回答
3

我在写这篇文章时感到畏缩,但是......

DerrivedClass::DerrivedClass(SomeParamType* p = new SomeParamType())
    : BaseClass(p),
      derrivedClassMember(p)
{
}

我现在需要去洗澡。无论如何,考虑到您的问题,是的,您的基本构造函数应该在初始化成员之前执行。成员必须按自上而下的顺序进行初始化,从构造函数中的基本成员开始并进行处理。

注意:我必须清理我的标准副本才能找到指定的位置,但我很确定它在那里,因为 lint喜欢告诉你乱序初始化警告及其不合规性。

于 2013-09-05T08:54:12.203 回答
2

当时还没有初始化。derrivedClassMember在初始化之前调用基类构造函数。这是因为派生类的派生成员或构造函数可能依赖于基类的成员。

于 2013-09-05T08:53:24.203 回答
2

总结一下现在给出的答案,再补充一点,有几个可能的解决方案。

1如果您的基类有成员的访问器,则相当简单:

DerrivedClass::DerrivedClass()
: BaseClass(new SomeParamType()),
  derrivedClassMember(getBaseClassMember()),
{
  ...
}

2在 C++11 中,使用委托构造函数,调用您发布的原始构造函数:

DerrivedClass::DerrivedClass()
: DerrivedClass(new SomeParamType())
{}

3在 C++03 中,使用默认参数(很难看):

DerrivedClass::DerrivedClass(SomeParamType* p = new SomeParamType())
    : BaseClass(p),
      derrivedClassMember(p),
{
 ...
}

4另一种解决方法,要摆脱 C++03 中的构造函数默认参数,将使用多重继承derivedclassMember在基类之前初始化:

struct DerivedClassInitializationWorkaround {
  SomeParamType* derivedClassMember:
  DerivedClassInitializationWorkaround(SomeParamType* param) 
    : derivedClassMember(param) {}
};

class DerivedClass : private DerivedClassInitializationWorkaround, //this has to go first!
                     public BaseClass {
public:
  DerivedClass::DerivedClass()
    : DerivedClassInitializationWorkaround(new SomeParamType())
    , BaseClass(derivedClassMember)
  {}
};

基类的初始化按照它们的声明顺序进行,因此如果您从 派生DerivedClassInitializationWorkaroundderivedClassMember它包含的 将首先初始化。

在任何情况下,您的代码都不是异常安全的。您不应将拥有指针存储为原始指针,而应使用智能指针。由于您无法更改基类,因此您必须确定它是否拥有该对象的所有权(即,它是否破坏了您传递给其构造函数的对象。

如果基类对象获得所有权,您或多或少会被现有的解决方案所困扰,除了派生类应该存储引用而不是指针,因为基类对象因此SomeParamType对象将比派生类的对象寿命长。

如果基类没有所有权,您应该存储一个unique_ptr

class DerivedClass : public BaseClass {
  unique_ptr<SomeParamType> derivedClassMember;

  DerivedClass::DerivedClass(unique_ptr<SomeParamType> param)
    : BaseClass(param.get())
    , derivedClassMember(move(param))
  {}

public:
  DerivedClass::DerivedClass()
    : DerivedClass(make_unique<SomeParamType>)
  {}
};
于 2013-09-05T09:24:09.687 回答
1

简短的回答是否定的,它是无效的。

这是您问题的一个很好的答案:

从派生类初始化列表调用基类构造函数的顺序

于 2013-09-05T08:58:30.197 回答