我正在寻找一种方法来创建一个必须由每个子类实现的方法。我还希望子类在构造时调用此方法。
在课程构建之后,不应该再次调用此方法。
#include <iostream>
class Base {
public:
Base() {init();}
private:
virtual void init() = 0;
};
class DerivedA : public Base {
public:
DerivedA() {}
private:
virtual void init() { std::cout << "Hello, I am A.";}
};
class DerivedB : public Base{
public:
DerivedB() {}
private:
virtual void init() {std::cout << "Hello, I am B.";}
};
int main(){
DerivedA a;
DerivedB b;
return 0;
}
这是一个示例,但它无效,因为它在构造函数中调用纯虚方法。当然,我可以在每个子类构造函数中添加init()
,但是在新的子类上可能会忘记它。
C ++的做法是什么?
答案 0 :(得分:4)
C ++方式是不这样做。 Init函数很糟糕。只需使用构造函数。
答案 1 :(得分:2)
AFAIK,在构造函数中调用虚函数是非常危险的。这是一个简单的例子。我稍微修改了您的代码,以便在init
类中实现Base
方法:
#include <iostream>
#include <exception>
class Base {
protected:
Base() {init() ; }
virtual void init() {
std::cout << "Init base" << std::endl;
}
public:
void callinit() {
init();
}
};
class DerivedA : public Base {
public:
DerivedA() {}
protected:
virtual void init() { std::cout << "Hello, I am A."<< std::endl;}
};
class DerivedB : public Base{
public:
DerivedB() {}
protected:
virtual void init() {std::cout << "Hello, I am B."<< std::endl;}
};
int main(){
DerivedA a;
DerivedB b;
a.callinit();
b.callinit();
return 0;
}
,输出为:
Init base
Init base
Hello, I am A.
Hello, I am B.
我们可以得出什么结论:
init
方法时,我们正常地从派生类中获得正确的实现但在构造函数中,顺序为:
Base
构造函数DerivedX
构造函数因此,该方法始终是来自Base
的方法,这绝对不是您所期望的。
答案 2 :(得分:0)
正如另一张海报所说,你应该远离这个,但最简单的例子是在Base上创建一个名为Init()的公共非虚拟接口方法,必须在构造对象后调用它。该方法可以在派生类上调用纯虚拟“DoInit”方法,并使用内部标志跟踪它是否已被调用。
我不推荐这个,但它会起作用。
class Base
{
public:
void Init()
{
if(!initialized)
{
DoInit();
initialized = true;
}
}
protected:
virtual void DoInit() = 0; // derived classes need to implement this
private:
bool initialized {false};
};
答案 3 :(得分:0)
我遇到了类似的问题,找不到简单的解决方案。我不得不在一个单独的类中进行初始化。此类的对象可以传递给Base / Derive构造函数,或者此类可以是模板参数。
class Initializer {
. . .
}
class Base {
public:
Base(Initializer* initializer) {
// Get members from initializer
}
}
或者:
template<Initializer TInitializer>
class Base<TInitializer> {
public:
Base() {
TInitializer initializer;
// Get members from initializer
}
}
抱歉,我没有用C ++写太长时间,所以我可以防止一些语法错误。
答案 4 :(得分:0)
C ++ 11的call_once可以帮到你,但它有成本。
它不会阻止多次调用该方法,但这很容易添加。
#include <iostream>
#include <mutex>
struct Base {
Base() {
std::cout << "Base ctor" << std::endl;
}
void sampleFunction1() {
// this line must be at the start of every function that needs the initialization
std::call_once(initedFlag, &Base::v_init, this);
std::cout << "Base::sampleFunction1" << std::endl;
}
void sampleFunction2() {
// this line must be at the start of every function that needs the initialization
std::call_once(initedFlag, &Base::v_init, this);
std::cout << "Base::sampleFunction2" << std::endl;
}
private:
virtual void v_init() = 0;
std::once_flag initedFlag;
};
请注意,Derived类没有任何特殊之处,只是它提供了v_init。
struct Derived : Base {
Derived() {
std::cout << "Derived ctor" << std::endl;
}
private:
void v_init() override {
std::cout << "Derived::v_init" << std::endl;
}
};
演示代码
int main(int argc, const char * argv[]) {
Derived d1;
Derived d2;
std::cout << "Calling d1" << std::endl;
d1.sampleFunction1();
d1.sampleFunction2();
std::cout << "Calling d2" << std::endl;
d2.sampleFunction2();
d2.sampleFunction1();
return 0;
}
输出:请注意,将调用v_init,首先调用样本函数,而不在ctors中调用。
Base ctor
Derived ctor
Base ctor
Derived ctor
Calling d1
Derived::v_init
Base::sampleFunction1
Base::sampleFunction2
Calling d2
Derived::v_init
Base::sampleFunction2
Base::sampleFunction1