我试图实现这样的目标:
class Base
{
public:
Base(string S)
{
...
};
}
class Derived: Base
{
public:
int foo;
string bar()
{
return stringof(foo); // actually, something more complex
};
Derived(int f) : foo(f), Base(bar())
{
};
}
现在,这不能正常工作,因为在foo初始化之前,在Derived构造函数中调用了bar()。
我考虑添加一个类似于bar()的静态函数,它将foo作为参数 - 并在初始化列表中使用它,但我想我会问是否有任何其他技术可以用来挖掘自己这一个...
编辑:感谢您的反馈 - 这是我将如何处理静态功能。不确定静态和非静态函数之间的重载是否太聪明,但是......
class Derived: Base
{
public:
int foo;
static string bar(int f)
{
return stringof(f); // actually, something more complex
}
string bar()
{
return bar(foo);
};
Derived(int f) : Base(bar(f)) , foo(f)
{
};
}
答案 0 :(得分:4)
是的,使用将 foo 作为参数并返回字符串的函数(静态类方法或常规函数)是一个很好的解决方案。您可以从Derived :: bar调用此相同的函数以防止代码重复。所以,你的构造函数看起来像这样:
Derived(int f) : Base(stringof(f)), foo(f) {}
我首先在列表中调用Base构造函数,以强调初始化发生的顺序。初始化程序列表的顺序无效,因为所有类成员都按照它们在类主体中声明的顺序进行初始化。
这是一个非常干净,functional解决问题的方法。但是,如果您仍想权衡替代方案,那么请考虑使用composition而不是继承来获取Derived和Base类之间的关系:
class Base {
public:
Base(string S) { ... }
void bat() { ... }
};
class Derived {
Base *base;
int foo;
public:
Derived(int f) : base(NULL), foo(f) {
base = new Base(bar());
}
~Derived() {
delete base;
}
string bar() {
return stringof(foo); // actually, something more complex
}
void bat() {
base->bat();
}
};
您需要根据具体情况考虑pros和缺点。使用Derived持有对Base的引用,您可以更好地控制初始化顺序。
答案 1 :(得分:4)
您只能在初始化列表中调用静态函数。你在代码中的方式:
class Derived: Base
{
public:
int foo;
string bar()
{
return stringof(foo); // actually, something more complex
};
Derived(int f) : foo(f), Base(bar())
{
};
}
仍将首先初始化Base,然后foo。在构造函数初始化列表中编写内容的顺序无论如何都无关紧要。它将始终按此顺序构建:
因此,您最终使用未初始化的值调用stringof
。 boost::base_from_member
解决了这个问题。另请注意,在完成所有基类的所有构造函数初始值设定项之前调用任何非静态成员函数是未定义的行为。
然而,调用静态函数是完全正常的:
class Derived: Base
{
public:
int foo;
static string bar(int f)
{
return stringof(f); // actually, something more complex
};
Derived(int f) : Base(bar(f)), foo(f)
{
};
}
答案 2 :(得分:2)
在初始化派生类的其他成员之前,始终会调用基类构造函数;你的编译器应该给你一个警告,让初始化器的顺序错误。唯一正确的解决方案是使bar()
成为一个以f
为参数的静态方法。
答案 3 :(得分:1)
构造函数用于构造对象。这意味着,在它返回之前,那里没有一个对象,因此调用成员函数不会可靠地工作。正如其他人所说,使用静态函数或非成员函数。
答案 4 :(得分:0)
我一直想要这样做,但最后我放弃了 任何合适的函数调用都可以用作Base()的参数 另一个选择是向Base添加和替代构造函数,它接受一个int并转换为'string'本身。
答案 5 :(得分:0)
只需将构造函数代码移动到Initialize()函数并从构造函数中调用它。这比静态/非静态覆盖或类似的东西简单得多。