棘手的多态性和虚函数
Tricky Polymorphism and virtual functions
我有以下代码:
#include <iostream>
using namespace std;
class K {
public:
virtual void add_st(K* n) {
cout << "add_st (K*) from Kn";
}
};
class L: public K {
public:
virtual void add_st(L* a) {
cout << "add_st (L*) from Ln";
}
};
int main() {
L ob, ob2;
K k, *pl = &ob;
pl->add_st(&ob2);
return 0;
}
程序的输出将是:
add_st (K*) from K
如果我没有错过任何东西的原因是虚函数表。对象从层次结构的顶部到最低的类生成。
但是这个代码:
#include <iostream>
using namespace std;
class K {
public:
virtual void add_st() {
cout << "add_st (K*) from Kn";
}
};
class L: public K {
public:
virtual void add_st() {
cout << "add_st (L*) from Ln";
}
};
int main() {
L ob, ob2;
K k, *pl = &ob;
pl->add_st();
return 0;
}
将打印
add_st (L*) from L
为什么?
虚函数在实参列表中是不变的,在返回类型中是协变的。
考虑这个问题的一个基本方法是,在基类中引入虚成员函数的地方,它定义了一个契约。
例如,给定
struct K
{
virtual K* add_st(K* n);
};
合约是 add_st
接受K
类型的任何对象(通过指针),并且返回K
类型的对象(通过指针)。
这将覆盖它
struct L : K
{
virtual K* add_st(K* a);
};
因为合同已明确履行,所以将:
struct M : K
{
virtual M* add_st(K* a);
};
,因为返回值是M
类型的对象,通过继承它也是K
类型的对象;
但这(问题中的情况)并不覆盖
struct N : K
{
virtual K* add_st(N* a);
};
因为它不能接受任何类型为K
的对象,只能接受类型为K
和N
的对象。
struct P : K
{
virtual K* add_st(void* a);
};
尽管从类型理论的角度来看,逆变参数是兼容的,但事实是c++支持多重继承,而且向上转换有时需要调整指针,因此逆变参数类型在实现级别就会中断。
它们将创建一个新函数(v表中的新槽),该函数将重载并隐藏现有函数,而不是覆盖它。(正如John Smith在他的回答中所说,可以使用using-declaration来避免隐藏基本版本)
下面是一个错误,因为签名是相同的,但返回类型是不兼容的:
struct Q : K
{
virtual void* add_st(K* a);
};
这里的结果可以是任何对象类型,但这还不够好,契约需要一个类型为K
的对象。它不能覆盖现有的函数,因为参数没有不同。所以它被拒绝了。
有关方差的更多细节,您可能需要阅读有关Liskov替换原理的内容。
首先,函数签名包括函数名及其参数类型。在第一个示例中,函数名称相同,但其参数类型不同。因此它们有不同的签名。因此,在第一个示例中,子类中的函数没有覆盖其父类中的函数。
其次还有overload
和名称隐藏的概念。在您的例子中,第一个示例中的函数定义隐藏了它的父函数。如果将父函数引入到同一作用域,则子函数将重载父函数,如下所示
class L: public K {
public:
using K::add_st;
virtual void add_st() {
cout << "add_st (L*) from Ln";
};
- 从基类调用函数的多态性
- C++多态性:有没有办法找到对象成员函数的地址?
- C++ 多态性:如果派生类中的虚函数在基类中声明了常量,是否需要将其声明为常量
- 如果基类指针无法访问派生类成员函数,那么多态性有什么方便的呢?
- 多态性在 lambda 函数C++不起作用
- 多态性是否适用于值?或者在按(基)值返回时使用派生类的移动构造函数
- 如何在保持多态性的同时,将成员函数添加到需要它的继承类中,而不会影响其他同级类?
- C++ 中多态性和函数重载之间的区别
- 函数模板和多态性
- C 多态性实例的构造函数和破坏者
- 多态性(C )的派生类中的超载函数
- 多态性和纯虚函数
- C++ 多态性和非虚函数
- C++多态性/虚拟函数在此不起作用
- 如果重载函数仅被部分重写,则多态性不起作用
- 多态性不适用于相同数据类型(Base和Inherited类)的函数返回值
- 具有引用数据类型的函数多态性
- c++在没有虚拟析构函数的多态性中共享ptr
- 模板函数多态性
- 基类和派生类构造函数多态性问题