我有 4 个重载函数vfoo
(3 个是虚拟的)
我试图在这里测试几个概念:
- 使用虚函数重载 当派生类实现了自己的重载函数
- 版本时,重载函数隐藏在派生类中。
- 基类指针存储派生类对象时的行为是什么
- 派生类中的重载函数,如 void vfoo( char x )
#include<iostream>
using namespace std;
/*Base class having 4 overloaded function*/
class ClassBaseV
{
public:
virtual void vfoo( int x ) {
cout << "ClassBaseV vfoo(int), x = " << x << endl;
}
virtual void vfoo( double x ) {
cout << "ClassBaseV vfoo(double), x = " << x << endl;
}
virtual void vfoo( int x, double y ) {
cout << "ClassBaseV vfoo(int,double), x = " << x << ", y = " << y << endl;
}
void vfoo( double x, int y ) {
cout << "ClassBaseV vfoo(double,int), x = " << x << ", y = " << y << endl;
}
};
class ClassDerived1 : public ClassBaseV
{
public:
//Overloaded with char x
void vfoo( char x ) {
cout << "ClassDerived1 vfoo(char), x = " << x << endl;
}
//over riding int x
void vfoo( int x ) {
cout << "ClassDerived1 vfoo(int), x = " << x << endl;
}
};
int main()
{
ClassBaseV *cB = new ClassDerived1(); /*Base pointer storing derived class object*/
ClassDerived1 *cd1 = new ClassDerived1(); //Derived class object
cd1->vfoo('a');//Direct call using derived class object. this works
char a = 'a';
cB->vfoo(a); // trying to call char x using cB. This calls derived class int How?
cB->vfoo(10); // trying to call int x using CB. This calls derived class int
cB->vfoo(2.2); // Wanted this to not to work as base class overloaded functions are hidden but this works
return 1;
}
如果重写派生类中重载集的一部分,通常的做法是使用 using
声明将所有未重写的函数放入作用域。防止令人尴尬的故障。
cB->vfoo(a); // trying to call char x using cB. This calls derived class int How?
Base 中的过载分辨率获得最接近的匹配项(字符 -> int)并使用虚拟调度进行调用
cB->vfoo(10); // trying to call int x using CB. This calls derived class int
与派生的过载分辨率和虚拟调度完全匹配。
cB->vfoo(2.2); // Wanted this to not to work as base class overloaded functions are hidden but
过载分辨率精确匹配,虚拟调度到基地。
切勿尝试删除派生类中的功能。
接口继承意味着:我最多需要基础需要的保证,我的行为符合基础合约。
"基类指针存储派生类对象时的行为是什么" - 这是多态性的核心思想。多态性基于基于在运行时确定的对象类型的特定行为,而重载函数在编译时解析。
常量文字的类型可以很容易地在编译时确定,10
int
,2.2
是double
,这将决定将使用哪个成员函数。然后,实例的类型将确定将使用哪个实现(哪个类)。下面是更简单的示例:
class Animal {
public:
virtual void makeSound(){ std::cout << "hi" << std::endl; }
virtual void makeSound(int pain){ std::cout << "ouch" << std::endl; }
virtual void makeSound(double d){ std::cout << "aaaaaaaargh" << std::endl; }
};
class Cat : public Animal {
public:
virtual void makeSound(){ std::cout << "meow" << std::endl; }
virtual void makeSound(int pain){ std::cout << "MEEEEEOW!!!" << std::endl; }
virtual void makeSound(double d){ std::cout << "meow double" << std::endl; }
};
int main() {
Animal *a = new Animal();
Animal *cat = new Cat();
a->makeSound();
cat->makeSound();
a->makeSound(100);
cat->makeSound(100);
cat->makeSound(750.80);
}
输出:
你好
猫叫声
哎哟
哎呀呀!!呀��
喵喵双
第一个问题:
cB->vfoo(a);
当你在这里调用vfoo时,它试图在ClassBaseV中找到vfoo(char x)的定义,但它没有,但仍然找到一个可以隐式转换为的vfoo(int x)的定义,所以它从ClassBaseV调用此方法。
编译器将尝试获取作为类型提供的类的方法定义。
ClassBaseV *cB = new ClassDerived1();
在此行中,键入 cB 作为指向 ClassBaseV 的指针。从现在开始,编译器不能查找方法定义(在子类中),但仍然可以查找方法定义,因为 ClassBaseV 知道对父类的任何可能的继承。
第二个问题:
cB->vfoo(2.2);
在这一行中,你调用方法vfoo(double x),因为在ClassBaseV中可以转换为double,并且你不会在ClassDerived1中覆盖此方法。
因此,调用此方法的 ClassBaseV 实现是一种正常行为。
如果你想调用 ClassDerived1 中覆盖的 vfoo 之一,你必须将其转换为 int 或 char(以及松散的信息)
cB->vfoo(static_cast<int>(2.2));
或者在 ClassDerived1 中添加一个新方法,覆盖 ClassBaseV 中的 vfoo(double x)。
另外,如果你想强制 ClassDerived1 从 ClassBaseV 实现方法 vfoo(double x),你必须将其声明为纯虚拟:
virtual void vfoo( double x ) = 0;