类的多态性
类的多态性
类的多态性
多个子类继承同一个父类实现相同的方法。
如果要 调用子类的方法必须把父类的方法声明为虚函数。
先声明父类的对象指向子类的内存空间,这样可以调用子类覆盖父类的
方法。
我想问的是也可以在子类中声明对象调用重写的方法。
在子类中调用和用父类用指针指向子类内存空间有什么区别和什么好处吗?
首先,
基类的指针可以指向继承类的Object 而无需 explict type cast,
基类的引用(reference) 可以引用继承类的Object 而无需 explict type cast,
但是,一个基类的 pointer 或者 reference 能,且仅能 调用基类的方法,也就是说一个基类的 pointer 或者 reference不能调用继承类的方法。
其次,
你不能将基类的 Objects 或 地址 赋于 继承类的 references 或 pointers
比如 A 为基类, B 为继承类
A a;
B & rb = a; // not allowed
B * pb = &a; // not allowed
从上面的描述你看到了
基类的 reference 和 pointers 可以指向继承类的objects, 也就是说
B b;
A & ra = b; // is allowed
A * pa = &b; // is allowed
这样就引出了下面的导论:
函数的参数如以基类的reference 或 pointer 作为参数,那么该参数可以访问基类的方法,也可以访问继承类的方法,由这一点又引出一个问题,如果在基类和继承类中有两个相同名字的函数,比如 在 A 中定义了方法
void func(){} 在 B中也定义了方法 void func(){// some code}
现在有一个函数:
void show(const A & ra)
{
ra.func();
}
那么这个func() 到底是基类中的func() 呢?还是继承类中的func() 呢?
这其实就是引出了我们为什么要引进 virtual 这个概念.
没有virtual 这个概念,我们上面这个func() 将是基类中的func(); 它取决于那个参数类型,也就是说,在参数中,那个类型为A,而A是基类,所以 ra 调用的是 基类中的那个 func().
而一旦我们引入了virtual 这个概念,那么这个判断就是另外个判断法了,比如:
class A
{
public:
virtual void func(){}
virtual ~A(){}
};
class B : public A
{
public:
void func(){ cout<<"haha";}
};
在main 中的代码如:
Aa;
B b;
A & a1_ref = a;
A & a2_ref = b;
a1_ref.func(); // 调用的是 A 的 func()
a2_ref.func(); // 调用的是 B 的 func()
也就是到底调用的是基类中函数还继承类中的函数,取决于所引用或所指向的对象.
这里我们看出来了,为什么C++ 引入了 virtual 这个概念.
再回到你的问题上来,诚如你所说的,假设C++ 没有 virtual 这个概念,那么当在继承类(子类)中的函数覆盖了基类(父类)中的函数时,继承类的对象将只能调用其该类中定义的函数.如果没有覆盖,将调用父类中的函数.
而有了virtual 以后,将使函数调用增加了灵活性,使本来做不到的事情成为了可能.这就是 virtual 带来的用处或好处.
现在观察下面的代码:
#include<iostream>
#include<cstdlib>
using namespace std;
class Father
{
public:
virtual void func(){cout<<"invoke base class function"<<endl;}
virtual ~Father(){}
};
class Son : public Father
{
public:
void func(){cout<<"invoke derived-class function"<<endl;}
};
int main()
{
Father father;
Son son;
Father & f1_ref = father;
Father & f2_ref = son;
f1_ref.func();
f2_ref.func();
son.func();
system("pause");
return 0;
}
我们来比较 f2_ref.func(); 和 son.func(); 它们之间有区别吗?回答是:它们之间没有区别,f2_ref 只是son的一个引用,也就是说,f2_ref 只是son的一个别名,也就是说,它们是同一个Object ,所以 f2_ref.func(); 和 son.func();它们之间是没有区别的.但是你看到了,由于存在了virtual我们通过父类的Object对子类的引用,从而调用子类的函数成为了可能,这样便给语言增加了灵活性,这也就是所谓的好处吧.
所以我们通常将函数定义成下面的形式:
ReturnType FunctionName(ParameterType & name); // Caution: 这里的ParameterType 为父类的类型,这样便使得该参数既可调用父类中的函数,又可调用子类中的函数.