从基类调用派生类函数

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 中定义的重写startstop 函数。

不过,有一个例外。如果您在base 的构造函数或析构函数中调用doSomething(无论是直接还是间接),那么被调用的startstop 的版本将是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 帮助,对不起,你的问题没有说清楚。很快就会更新。

以上是关于从基类调用派生类函数的主要内容,如果未能解决你的问题,请参考以下文章

如何从基类调用派生类函数?

如何从基类调用派生赋值运算符?

从基类c ++的向量中的派生类调用虚拟方法[重复]

使用纯多态性和继承从基类调用派生类上的函数而不进行强制转换?

派生类不从基类继承重载方法

如何从基类调用派生类方法?