class base
{
public:
virtual void start();
virtual void stop();
void doSomething() { start(); .... stop(); }
}
class derived : public base
{
public:
void start();
void stop();
}
但是当我在派生类中调用doSomething()
时,它正在使用它自己对Start()
和Stop()
的定义 - 而不是派生类。
我不想在派生类中重写doSomething()
,因为它与基类相同。我做错了什么?
对不起,如果不清楚的话 派生类中Start()和Stop()的行为是不同的(它是一个不同的机器) - 但我想使用原始基类doSomething(),因为它没有改变。它只需要使用新的派生类代码start()和stop()。
答案 0 :(得分:23)
您发布的代码应该按照您想要的方式运行。在doSomething
的实例上调用derived
会调用start
中定义的被覆盖的stop
和derived
个函数。
但是有一个例外。如果在doSomething
的构造函数或析构函数中调用base
(无论是直接还是间接),那么调用的start
和stop
版本将是base
。那是因为在这种情况下,您实际上还没有有效的derived
实例。它不是完全构造的或部分破坏的,因此该语言阻止您调用将使用部分对象的方法。
如果您没有从base
构造函数或析构函数中调用它,那么问题就会出现问题,而不是此处显示的内容。
答案 1 :(得分:7)
更新的
根据您在下面的评论,您试图让doSomething()调用Derived类的start()和stop()版本,我对您的问题的更新答案如下:
您定义Base和Derived的方式没有任何问题。您可能正在经历所谓的“代码切片”,您在声明类型为“Base”的对象上调用“doSomething()”,而不是“Base *”或“Base&”,这将导致对象被转换为Base类型。
错误的例子:
Derived derived;
Base base = derived;
base.doSomething(); // This is Base's version of doSomething()
很好的例子:
Base* base = new Derived; // NOTE: declared type is "Base*"
base->doSomething(); // This will call Derived version
delete base;
旁注:您应该使用scoped_ptr,shared_ptr,unique_ptr或其他一些智能指针类,而不是像我的示例中那样直接使用指针;但是,为了不掩盖这个问题,我选择在这个例子中使用原始指针。有关“切片”的更多信息,请参阅:
原始解决方案
你可以这样做:
class Base {
public:
Base() {}
virtual ~Base() {}
virtual void start() {
startInternal();
}
virtual void stop() {
stopInternal();
}
void doSomething() {
startInternal();
// ...
stopInternal();
}
private:
void startInternal() {
// ...
}
void stopInternal() {
// ...
}
};
class Derived : public Base {
public:
Derived() {}
virtual ~Derived() {}
virtual void start() {
// ...
}
virtual void stop() {
// ...
}
};
如果你这样做,那么doSomething()将使用未被覆盖的内部版本的start / stop。当构造函数/析构函数需要与虚方法共享逻辑时,您会发现很多这种模式。
此外,与手头的问题无关,请不要忘记,每当创建具有虚方法的类时,都应始终创建虚拟析构函数。
答案 2 :(得分:1)
只需在基类中将启动和停止函数声明为纯虚函数即可。
virtual void stop() = 0;
virtual void start() = 0;