如果派生类重写基类方法,为什么要调用基类方法
Why is the base class method called if the derived class overrides the method?
考虑以下程序:
class Base {
public:
virtual void foo() const {
cout << "Base::foo()" << endl;
}
};
class Derived : public Base {
public:
virtual void foo() {
cout << "Derived::foo()" << endl;
}
};
void func(Base& obj) {
obj.foo();
}
void main() {
Derived d;
func(d); // Base::foo() is printed
}
如果我从Base
类foo
方法中移除const
,则调用Derived::foo()
。我似乎无法理解这种行为。
1) 这种行为的原因是什么?
2) 这是在编译时还是在运行时决定的?
感谢
在派生类中,函数签名如下:
virtual void foo(); //Derived::foo
其中没有提到CCD_ 5。它是一个非常数成员函数,而Base::foo
是一个常量成员函数。它们是两个不同的函数,因为const
是函数签名的一部分。
virtual void foo() const; //Base::foo
派生类并没有覆盖这个函数,而是添加了另一个函数。
因此,解决方案是:
class Derived : public Base {
public:
virtual void foo() const {
cout << "Derived::foo()" << endl;
}
};
由于const
是函数签名的一部分。所以当您打算覆盖base的foo时,必须提到它。
@davka问:
那么,为什么选择常量版本而不是非常量版本呢?有什么规则吗?或者这只是第一个选项?
这是因为obj
的静态类型是Base
,并且函数名称是根据对象的静态类型解析的。Base
甚至没有非常量版本。因此,它不存在被选中或被拒绝的问题。它一开始并不存在于Base
中。
void func(Base& obj) {
obj.foo(); //calls Base::foo
}
但是,如果您将上述代码更改为以下代码:
void func(Derived & obj) {
obj.foo(); //calls Derived:foo
}
现在将选择非常量版本,因为Base::foo
隐藏在Derived
类中。
由于Derived::foo
隐藏了Base::foo
,因此不能使用Derived
的实例调用后者。
现在,让我们取消隐藏Base::foo
并进行更多的实验。
class Derived : public Base {
public:
using Base::foo; //<----------------this unhides Base::foo
virtual void foo() {
cout << "Derived::foo()" << endl;
}
};
现在,在Derived中,这两个函数(const和非常量版本)都可用,但未隐藏。现在有几个有趣的问题。
由于现在Derived已取消隐藏这两个函数,下面的每个函数将调用哪个函数?
void f(Derived& obj) {
obj.foo(); //Which function? Base::foo or Derived::foo?
}
void g(const Derived & obj) {
obj.foo(); //Which function? Base::foo or Derived::foo?
}
第一个将调用非常量版本的Derived::foo
,第二个将调用常量版本的Base::foo
。原因很简单,对于const对象,只能调用const函数,但对于非常量对象,两者都可以调用,但如果非常量版本可用,则会选择它。
查看在线演示:http://www.ideone.com/955aY
您没有重写该方法,因为Derived::foo
并不完全相同。
要重写方法,基本版本和重写版本必须相同,包括const
-ness。
在C++中,可以有两个具有相同名称和参数的函数,其中唯一的区别是const
,而不是。
这个想法是,你有时想要不同的行为。例如,一个访问函数可能有不同的返回类型:
class MyClass
{
public:
virtual Xxx * GetXxx();
virtual Xxx const * GetXxx() const;
// ....
}
您可以单独覆盖这些功能。
在您的情况下,当您从非常量对象调用foo
时,您调用了函数的非常量变量。由于您已经重写了const变量,基类中的变量就是被调用的变量。
您所做的被称为"重载"。正如@SLaks所指出的,在重写时,签名需要相同。
const
是签名的一部分。CCD_ 26是与CCD_ 27不同的函数。你根本没有压倒一切。这就是为什么。
- 使用子类覆盖基类中定义的函数
- 如何基于模板化类的基类专门化成员函数
- 永久更改派生类的基类?
- C++初始化之前派生类调用基类的方法
- 如何从派生类访问基类中的重载运算符?
- CRTP 如何使派生类具有基类的容器
- 如何删除派生类中基类对象的新对象
- 是否可以从派生类返回基类的实例?
- C ++中有没有办法让派生类重写基类静态方法
- C++多态性模板类:调用基类方法而不是派生类
- 从派生类实现基类构造函数专用化的替代方法是什么
- C++-从方法基类调用派生类中的重写方法
- 从基类调用基类中不存在的派生方法
- c++中没有从派生类调用基类方法的匹配函数
- C++派生类调用基类方法给出了分段错误
- 子类调用基类构造函数,然后使用子类Arduino c++中基类的实例方法
- 通过多级继承从模板子类调用基类的模板方法
- 如果派生类重写基类方法,为什么要调用基类方法
- 在c++中是否可以从派生类调用基类中的方法?
- 需要从c++中的派生类调用基类析构函数方法