我派生了类和基类。在派生类的构造函数中,我必须使用基类的基本构造函数。然后我想用deiffernet基类构造函数重新构造基类:
class A
{
public:
int a, b;
}
class B : public A
{
B() : A()
{
...
//do some calculations to calculate a and b and then
//re-construct class A with the right values.
A(a,b) <--- ????
}
}
我该怎么做?
答案 0 :(得分:6)
构造函数用于创建对象。因此它们被使用一次。您应该创建一个方法来进行初始化并从构造函数中调用它。
答案 1 :(得分:1)
您可以在class A
中提供复制和/或移动作业。
class A
{
public:
int a, b;
// Copy assignment operator
A& operator=(const A& rhs) {
if(this == &rhs) return *this;
a = rhs.a; b = rhs.b;
return *this;
}
// ...
};
完成上述操作后,您可以使用模式
重新初始化它BaseClass::operator=(BaseClass(a,b));
,在你的情况下是
A::operator=(A(a,b));
如果您的类是聚合,或者具有隐式定义的复制构造函数,您应该使用它们(您不必定义自己的类),并使用与上面相同的重新初始化模式。
答案 2 :(得分:1)
正如其他人已经指出的那样,你只能在当前构造函数的初始化列表中调用固有的构造函数,或者(在C ++ 11中)委托给当前类的其他构造函数。这是您初始化课程的唯一地方。
在某些情况下,添加init()
方法是有意义的,该方法会重新初始化您课程的某些部分。这称为两阶段初始化。您可以在一些窗口管理API中找到它。
重要的是要注意,您的对象然后被分成两部分:在c&#tor;中有用地初始化的对象,以及在init()
中初始化的另一部分。您必须(必须,必须!)以对象处于一致状态的方式初始化两个部分 - 绝不能处于无效状态。根据经验:如果创建对象(通过c),则必须始终可以进行析构函数调用。特别是:不要随意留下任何指针和句柄。
class ChildWindow : Compontent {
shared_ptr<Component> parent_; // builds the component hierarchy
Component[] children_; // child cp'nts, unknown during c'tor
size_t nchildren_; // ...use e vector in real code!
public:
ChildWindow(chared_ptr<>Component> parent)
: parent_(parent),
children(nullptr), nchildren(0) // MUST initialize
{}
void addChild(Component *child) { /*... change children_ ...*/ }
void init() {
if(nchildren > 0) { /* ...throw away old ... */ }
children_ = new Component[...];
// ... init children_ with nulls
}
};
这只是一个粗略的想法,您可以使用两阶段初始化。
如果你真的只需要重新初始化所有内容,那么技术解决方案可能会在你的真实对象周围使用一个简单的包装类:
class WindowWrapper {
Window *window_;
public:
WindowWrapper() : window_(nullptr) {}
void reset() { delete window_; window_ = nullptr; }
Window& get() { return *window_; }
Window& operator*() { return get(); }
}
...键入了副手,可能是其中的一些错误。这就是C ++ 11中已经是这样的包装器的原因:
unique_ptr<Window> win { new Window{parent, "title"} };
// ..use win...
win.reset( new Window{otherparent, "other title"} };
如果这个unique_ptr
不够,你可以把它放在上面的包装器中。
正如旁注,解释你所编写的代码的作用:
B::B() : A() {
A(a,b); // <--- ????
}
当您键入行&#34; ????&#34;时,您创建一个类型为A
的*临时对象,该对象在函数退出时消失。它不调用当前对象上的任何析构函数。
为什么要创建临时对象?好吧,你可以写
A a(a,b);
作为一个语句,你得到一个类a
的新实例A
,用一个带有两个参数的c&#39;来构造。您可以在另一个函数调用中使用此a
,例如func(a);
。但是你可以通过省略它的名字来保留那个显式变量a
:
func(A(a,b));
使用类func
的未命名(&#34;临时&#34;)对象调用A
,该对象在语句末尾消失(即;
)。
您可以将这些临时对象创建为表达式。因为每个表达式也是语句
A(a,b);
是一个有效的语句 - 创建一个临时对象,它会立即消失。
答案 3 :(得分:0)
除初始化列表外,您无法调用超类的构造函数。如果要对不同构造的A对象使用操作,则必须使用组合而不是继承。如果方法更改已构造的对象,则它不是构造函数。因此,要么用新构造的对象替换对象(而不是更改它),要么使用非构造函数方法。
答案 4 :(得分:0)
将代码计算为a和b计算方法并在初始化列表中使用它:
class A {
public:
A(int a, int b): a_(a), b_(b) {}
};
class B : public A
{
public:
B(): A(B::computeA(), B::computeB()) {}
private:
static int computeA();
static int computeB();
};
我已将方法设为静态以防止使用部分初始化的对象。
虽然我不得不说问题和示例听起来像是在使用继承来重用实现。在这种情况下,您不应该使用继承而是使用组合,并将继承替换为成员对象。