从基类调用派生类函数
Posted
技术标签:
【中文标题】从基类调用派生类函数【英文标题】:Calling derived class function from base class 【发布时间】:2011-06-19 15:30:09 【问题描述】: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()。
【问题讨论】:
当然使用自己的定义;这就是工作中的多态性。你的问题不是很清楚,为什么不想调用覆盖的实现? 欢迎来到 Stack Overflow。请考虑花更多时间准备您的问题,以便准确地展示您希望讨论的问题。这意味着发布一个简短的、可编译的和可运行的示例。准备好后,从代码编辑器复制并粘贴到浏览器中;不要尝试在浏览器中编写新代码,因为你会犯错误,而且读者也不清楚这些错误是否真的是你的测试用例的一部分。 @EdSwangren:我相信他想扩展行为。在这种情况下,在派生类调用 base::start() 中的 start() 和 stop() 的实现中;和 base::stop();分别处理派生的细节。要么,要么使启动和停止纯虚拟,并将常见行为封装在受保护的函数中。 @The_drow,如果问题是它使用了错误的函数实现,这显然不是编译器错误。这在编译时不可能知道,因此实际代码必须是可运行的。但总的来说,你是对的——如果问题是它无法编译,那么发布可运行代码的要求就被放弃了。 @cpp:你确定这句话说的是你想要它说的话:“但是当我在派生类中调用doSomething()
时,它使用的是它自己的定义Start()
和 Stop()
- 不是派生的。” [强调我的]?因为如果是这样,我什至不明白你的问题是什么。
【参考方案1】:
您发布的代码应该按照您想要的方式工作。在derived
的实例上调用doSomething
将调用derived
中定义的重写start
和stop
函数。
不过,有一个例外。如果您在base
的构造函数或析构函数中调用doSomething
(无论是直接还是间接),那么被调用的start
和stop
的版本将是base
中定义的版本。那是因为在这种情况下,您实际上还没有有效的 derived
实例。它要么未完全构造,要么部分破坏,因此该语言会阻止您调用将使用部分对象的方法。
如果您不是从 base
构造函数或析构函数调用它,那么问题比这里显示的要多。
【讨论】:
【参考方案2】:更新 根据您在下面的评论,您试图让 doSomething() 调用派生类的 start() 和 stop() 版本,我对您的问题的更新答案如下:
您定义 Base 和 Derived 的方式没有任何问题。您可能正在经历所谓的“代码切片”,您在声明类型为“Base”而不是“Base*”或“Base&”的对象上调用“doSomething()”,这将导致对象被转换为 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 或其他一些智能指针类,而不是像我的示例中那样直接使用指针;然而,为了不掩盖这个问题,我选择在这个例子中使用原始指针。有关“切片”的更多信息,请参阅:
What is the slicing problem in C++? - *** Slicing in C++原方案 你可以这样做:
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() 将使用未覆盖的内部版本的启动/停止。当构造函数/析构函数需要与虚方法共享逻辑时,您会发现这种模式很多。
此外,与手头的问题无关,不要忘记,无论何时创建具有虚拟方法的类时,都应始终创建虚拟析构函数。
【讨论】:
@Marton,无论 start() 和 stop() 是否在 Derived 中声明为虚拟,它们都将是虚拟的(在具有相同签名的基类中声明为虚拟的方法在派生类)。就风格而言,我更喜欢将它们重新声明为虚拟,以明确它们是虚拟的,而无需查找基类的文档。 注意:我上面的评论是对 Marton 删除评论的回应,该评论询问我是否打算在派生类中也将 start() 和 stop() 设为虚拟。 这与我所需要的相反 - 我需要基类 doSomething() 在派生类中调用 doSomething() 时获取派生的开始/停止。 @RageD,这完全是风格问题。我现在习惯于使用 Google C++ 风格(参见:google-styleguide.googlecode.com/svn/trunk/…),其中声明“重新定义继承的虚函数时,请在派生类的声明中明确声明它为 virtual。理由:如果省略 virtual,读者必须检查相关类的所有祖先以确定该函数是否是虚拟的。”我认为给出的理由是有道理的。 @cpp 帮助,对不起,你的问题没有说清楚。很快就会更新。以上是关于从基类调用派生类函数的主要内容,如果未能解决你的问题,请参考以下文章