【问题标题】:Force a derived-class object to use its own function, not the base-class one强制派生类对象使用它自己的函数,而不是基类函数
【发布时间】:2016-11-26 18:26:05
【问题描述】:

我对 C++ 中的子类有些怀疑。我有这个代码:

class BaseClass() {
    BaseClass();
    void doSomething();
}

class SubClass : public BaseClass {
    SubClass();
    void doSomething();
}

当我声明一个可能是子类的 BaseClass 对象时,我会调用子构造函数...

BaseClass foo = SubClass();

然后我需要 foo 使用派生类的 doSomething() 方法,但是当我这样做时......

foo.doSomething();

它使用父类方法而不是派生方法。我试过了,但它不起作用:

foo.SubClass::doSomething();

有什么方法可以做到吗,或者我不得不用“SubClass”类型声明对象以使其使用自己的功能?

【问题讨论】:

  • virtual void doSomething();??
  • BaseClass foo = SubClass(); -- fooBaseClass 类型的对象,而不是 SubClass。这是对象切片的示例。并且标记doSomething() virtual 不会改变这一点。
  • 是的,正如 Pete Becker 所说,这似乎是一个对象切片问题,所以将函数设为虚拟并不能解决问题......解决这个问题的唯一方法是将 foo 显式声明为 SubClass 类型,不是吗?

标签: c++ inheritance polymorphism object-slicing


【解决方案1】:

问题一:对象切片

在你的初始化中

BaseClass foo = SubClass();

您创建一个匿名临时 SubClass 对象并复制构造一个 BaseClass 对象。这意味着 foo 是并且仍然是从 SubClass 复制的 BaseClass

这称为object slicing。如果baseClass 有数据成员,则子类的相应数据成员将被复制到其中。如果SubClass 有额外的数据成员,这些将丢失。

如果您想使用BaseClass 对象,但又不丢失其真实类型的成员,无论是基类还是派生类,您都需要使用引用或指针:

BaseClass *foo = new SubClass;  // foo is a base class pointer but points to a SubClass object. 

SubClass bar;  
BaseClass& foo2 = bar;          // foo2 is a base class REFERENCE which refers to a Subclass object

但是,这还不够。

问题2:多态性

如果你现在调用该方法:

foo->doSomething();  
foo2.doSomething(); 

它仍然是BaseClass::doSomething(),尽管指向/引用的对象的真实类型。这是因为对于普通的成员函数,编译器会尝试在编译时识别要调用的函数:而在编译时它只知道指针或引用的类型。

要从多态行为中受益,您还需要将函数定义为virtual,如Johan 所述。在这种情况下,编译器将生成代码,只需一点开销即可动态识别对象的类型,因此会完全按照您的预期调用正确版本的函数。

请注意,如果您的基类中至少有一个虚函数,您最好为它声明一个虚析构函数。

【讨论】:

    【解决方案2】:

    使用虚拟和覆盖:

    class BaseClass() {
        BaseClass();
        virtual ~BaseClass() = default;
        virtual void doSomething();
    }
    
    class SubClass : public BaseClass {
        SubClass();
        void doSomething() override ;
    }
    

    编辑:正如 Christophe 所说,使用上面的虚拟析构函数。

    【讨论】:

    • 是的!但最好预见一个虚拟析构函数。
    【解决方案3】:

    你可以在BaseClass中声明dosomeThing方法virtual,比如

    virtual void doSomething()
    {
       ----
    }
    

    【讨论】:

    • 这个面向对象编程的概念叫做多态性
    猜你喜欢
    • 2010-12-26
    • 2012-09-28
    • 2019-01-09
    • 2011-09-16
    • 2011-09-27
    • 2014-01-01
    • 2020-09-06
    • 1970-01-01
    • 2012-06-01
    相关资源
    最近更新 更多