在C ++中的其他一些指令之后调用基类的构造函数

时间:2011-05-05 08:46:57

标签: c++ oop class

据我所知,无法调用基类的构造函数。我知道的唯一方法就是:

MyClass::MyClass(/* args */) : Base(/* args */)
{
   // ...
}

但这会在开头调用构造函数。 有没有办法在构造函数中的其他地方调用它?像这样:

MyClass::MyClass(/* args */)
{
   // ... instructions
   Base::Base(/* args */);
   // ... other_instructions
}

根据这个What are the rules for calling the superclass constructor?问题我理解没有办法,但我读了here,我猜想这是可能的,但如果我尝试,我会得到:

error: invalid use of 'class Base'.

我做错了吗?是否有可能以某种方式做到这一点,还是有其他可能的解决方案来满足这种需求?

谢谢!

编辑:我理解我忘记了一个关键点:基类是框架的一部分,因此如果可能的话,最好不要修改它。

7 个答案:

答案 0 :(得分:20)

如果基类构造函数至少使用一个参数,则可以使用这样的辅助函数:

int DoStuffBeforeCtorAndForwardInt(int arg, Foo foo)
{
    DoStuff(arg, foo);
    return arg;
}

MyClass::MyClass(int arg, Foo foo)
    : Base(DoStuffBeforeCtorAndForwardInt(arg, foo))
{
   // ...
}

如果要默认初始化基类,可以使用copy-ctor复制默认的初始化基类实例:

Base DoStuffBeforeCtorAndReturnDefaultBase(int arg, Foo foo)
{
    DoStuff(arg, foo);
    return Base();
}

MyClass::MyClass(int arg, Foo foo)
    : Base(DoStuffBeforeCtorAndReturnDefaultBase(arg, foo))
{
   // ...
}

或者,如果Base不必是第一个基类,则可以从帮助程序类派生MyClass

MyClass::MyClass(/* ... */)
    : DoStuffHelperClass(/* ... */),
    Base(/* ... */)
{
   // ...
}

以上所有要求你所做的“东西”不依赖于即将被初始化的对象(即函数不能安全地成为成员函数,你不能安全地传递this作为参数他们要么)。

这意味着您可以执行一些日志记录或类似操作,但在基类初始化之后,您也可以再次执行此操作。

EDIT 除了使用DoStuffHelperClass解决方案,您当然可以在DoStuffHelperClass中拥有成员,访问它们以及什么不是)


虽然我不得不说我不记得曾经使用/需要/想要这样的东西。对于你正在尝试做的事情,很可能还有另一个(更好的)解决方案。

答案 1 :(得分:9)

使用base-from-member idiom在“真正的”基类(基础)的ctor之前运行代码:

struct Base {
  Base(string, int);
};

struct DerivedDetail {
  DerivedDetail() {
    value = compute_some_value();
    value += more();
    value += etc();
    other = even_more_code(value);
  }
  string value;
  int other;
};

struct Derived : private DerivedDetail, Base {
  Derived() : Base(value, other) {}
  // In particular, note you can still use this->value and just
  // ignore that it is from a base, yet this->value is still private
  // within Derived.
};

即使您在DerivedDetail中没有您想要的实际成员,这也可以。如果你在Base的ctor之前详细说明你必须做的事情,那么我可以给出一个更好的例子。

答案 2 :(得分:8)

在开始构建自己的类之前,基类始终是完全构造的。如果需要更改基类的状态,则必须在构造完成后明确地执行此操作。

示例:

MyClass::MyClass()
{
    // Implicit call to Base::Base()

    int result = computeSomething();
    Base::setResult(result);

    // ... 
}

答案 3 :(得分:2)

除了已经编写的解决方案之外,您还可以使用静态构造函数并使MyClass的构造函数成为私有。

class QtBase{
  // ...
};

class MyClass : public QtBase{
public:
  // copy ctor public
  MyClass(MyClass const& other);

  static MyClass Create(/*args*/){
    // do what needs to be done
    int idata;
    float fdata;
    // work with idata and fdata as if they were members of MyClass
    return MyClass(idata,fdata); // finally make them members
  }

  static MyClass* New(/*args*/){
    int idata;
    float fdata;
    // work with idata and fdata as if they were members of MyClass
    return new MyClass(idata,fdata); // finally make them members
  }

private:
  // ctor private
  MyClass(int a_idata, float a_fdata)
    : idata(a_idata)
    , fdata(a_fdata)
  {}

  int idata;
  float fdata;
};

现在您必须将MyClass的实例创建为:

MyClass obj = MyClass::Create(/*args*/);

MyClass* ptr = MyClass::New(/*args*/);

答案 4 :(得分:0)

不,因为它不是类型安全的。
认为你有:课程A和变量A.var
现在考虑B继承自A,并在var初始化之前使用A。你会得到一个运行时错误!语言想要防止这种情况,因此必须首先初始化超类构造函数。

答案 5 :(得分:0)

不,你不能这样做,正如其他人在之前的回答中所描述的那样。

你唯一的机会是组合,IOW MyClass使用Base类作为成员字段:

class MyClass {
public:
   /** the methods... */

private:
   Base* _base;
};

因此,当您拥有所需信息时,可以稍后初始化_base。无论如何,我不知道这是否适用于你的场景。

答案 6 :(得分:-1)

没有。这是不可能的,因为构造函数调用的顺序是由标准严格定义的。必须在执行派生类ctor之前执行基类ctor。