C++语法之多态

来源:互联网 发布:学霸君答疑知乎 编辑:程序博客网 时间:2024/06/05 00:45

下面简单介绍下我对C++语法-->多态的理解

一、首先我们要知道什么是多态?

我的理解是:如果将基类中的某个成员声明为虚函数,那么子类中与该函数具有相同原型的
成员函数也是虚函数,并且对基类中的版本形成了覆盖,这时通过指向子类对象
的基类指针或者引用调用该虚函数时,实际被执行的是子类中的覆盖版本。而不
是基类中的原始版本,这种语法现象称为多态。

eg:class A{public:virtual void foo(){}//虚函数  函数前加virtual};class B:public A{public:void foo(){}//该函数也会成为虚函数,并A中的foo形成覆盖};int main(){B b;//建立B类的对象A *p = &b;//P指针指向的B类的对象b,但是P指针的类型是A类的(向上造型)p->foo();//通过p调用foo函数,实际执行的是B类中的foo函数return 0;}

二.虚函数的覆盖条件和函数重写的要求:
  1.只有类当中的函数才能被声明成虚函数,而全局函数、类中的静态成员函数、
构造函数,都不能声明为虚函数(析构函数例外,下面说明)。
   2.虚函数必须在基类中被virtual修饰,才能被子类版本覆盖,而与子类版本中
是否加virtual无关。
   3.基类中的虚函数必须和子类中的覆盖函数函数名、参数、常属性、完全一致
  4.如果基类中的虚函数返回的是基类类型,那么子类中的覆盖函数必须返回相同的
类型。
  5如果基类的虚函数返回的是类类型的指针或引用,那么允许子类的覆盖版本返回其
子类类型的指针或引用。


三.多态的条件
   1.除了满足虚函数覆盖以外,还必须通过指针或者引用去调用这个虚函数,才能
表现出来。
   2.调用虚函数的指针也可以是this指针,只要他是一个指向子类对象的基类指针。(下
面做下说明)

   class A{    public:void func(void){}   };   class B:public A{   };
上面代码中,B类继承了A类中的func函数,在A类中函数实际为:void this->func(){}
他有一个A类型的指针指向它。
B类继承了以后,相当于在B类中也有了func函数,但是此时的this指针是A类的,指向的
是B类中的func函数。


四.纯虚函数、抽象类、纯抽象类
1.什么是纯虚函数?
当基类中的虚函数仅仅是为了方便子类的函数取覆盖的时候(没有实际功能),我们把基类中
的虚函数声明为:
virtual 返回类型 函数名(形参表)[const]=0;
这时,这个函数就叫做纯虚函数。
2.什么是抽象类?
类中有纯虚函数的类就叫做抽象类。
3.什么是纯抽象类?
一个类中所有的函数都是纯虚函数,那么该类就是纯抽象类。


五.虚析构函数
1.虚构函数可以成为虚函数吗?
可以!
2.为什么把析构函数设置为虚函数?
为了避免内存泄露。以下具体说明。
参照第一个代码(A为基类,B为子类):

B b;A *p = &b;delete p;
当我们delete p时,执行的析构函数仅为基类的析构函数,子类的析构函数不会被执行(该指针
是基类类型的),如果把基类的析构函数设置为虚函数,子类的析构函数将会对基类的析构函数
形成覆盖,这时候执行的就是子类的析构函数,子类的析构函数执行完之后又会自动执行基类的
析构函数,这样可以防止内存的泄露。

六.多态的内部实现(个人理解):
多态的内部是通过虚函数表和动态绑定类实现的。
当一个类中有虚函数时,编译器会为该类生成一个虚函数表,该表是一个函数指针数组,数组的
每个成员存着每个虚函数的地址。在类中编译器还会生成一个指针来指向该表(数组)。子类中
的函数对基类中函数的覆盖就是覆盖掉了表里的指针,更改了指针的指向(指向了子类中的函数)。


原创粉丝点击