C++多态

青春壹個敷衍的年華 提交于 2020-02-16 09:51:28

1概念

多态:不同类型对象调用相同接口完成不同的行为。

1.1覆盖(重写override)成立的三个条件

1.继承
2.子类覆盖(重写)父类虚函数
3.父类指针/引用指向子类

1.2虚函数定义规则:

  1. 如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,有无const. 那么即使加上了virtual关键字,也是不会覆盖。
  2. 只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。
  3. 静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。
  4. 内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义,但是在编译的时候系统仍然将它看做是非内联的。
  5. 构造函数不能是虚函数,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。
  6. 析构函数可以是虚函数,而且通常声明为虚函数。

1.3多态的实现原理分析

当类中声明虚函数时,编译器会在类中生成一个虚函数表(基类和派生类中各自都会生成一个)

1.4虚函数表

  1. 虚函数表是一个存储类成员函数指针的数据结构
  2. 虚函数表是由编译器自动生成和维护
  3. virtual函数会被编译器放入虚函数表中
  4. 存在虚函数时,每个对象当中都有一个指向虚函数表的指针(vptr指针)

1.5纯虚函数

纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加=0

class 类名{
    virtual 返回值类型 函数(形参列表) = 0;
}

1.6抽象类

包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象

1.7重载覆盖的区别

重载 覆盖
重载要求函数名相同,但是参数列表必须不同,返回值可以相同也可以不同。 覆盖要求函数名、参数列表、返回值必须相同
在类中重载是同一个类中不同成员函数之间的关系。 在类中覆盖则是子类和基类之间不同成员函数之间的关系。
重载函数的调用是根据参数列表决定 覆盖函数的调用是根据对象类型决定
重载函数是在编译时确定调用一个函数 覆盖函数是在执行时确定调用个函数。

1.8代码如何判断是否调用了覆盖函数

#include<iostream>
using namespace std;
class A{
public:
	A(){

	}
	virtual ~A(){

	}
	virtual void Function()const{
		cout<<"A::FUNC"<<endl;
	}
	void Function(int n)const{
		cout<<"A::FUNC("<< n<<")"<<endl;

	}

};	

class B:public A{
public: 
	using A::Function;
	B(){

	}
	~B(){

	}
	void Function()const{  //同名隐藏规则
		cout<<"B::FUNC"<<endl;
		A::Function();
	}


};
int main(){

	B b;
	b.Function();//调用b的
	//b.Function(1);//报错
	//两种解决方法
	//1.b.A::Function()
	//2. using A::Function;
	A*p=new B;//创建B A
	//一般来说,类型决定成员调用;但是多态是对象决定成员的调用
	
	//多态3点
	//1:赋值规则
	//2:父类有虚函数
	//3:子类中有虚函数的实现
	
	p->Function();//多态
	delete p;

有个问题:因为p指针是A类型 所以delete后 只忻构A 而B不析构

	//解决方法 :在A中  将析构函数变成虚函数
	p=NULL;
	//原则:如果一个类或者它的父类存在被继承和虚函数  那么必须定义虚析构
	
	cout<<"---------------------------"<<endl;
	//另一种多态的方法
	A &r=b;
	r.Function();
	
}	

引用和指针相同的判断方式
在这里插入图片描述

1.9测验

#include <iostream>

using namespace std;

class Base{
    public:
    Base(){
        cout << "Base constuct" << endl;
    }
    ~Base(){
        cout << "Base destuct" << endl;
    }
};
class Member{
public:
    Member(){
        cout << "Member constuct" << endl;
    }
    ~Member(){
        cout << "Member destuct" << endl;
    }
};
class Derive:public Base{
public:
    Derive(){
        cout << "Derive constuct" << endl;
    }
    ~Derive(){
        cout << "Derive destuct" << endl;
    }
private:
    Member m;
};
int main(){
    Base* pD = new Derive;
    delete pD;
}

答案

[root@foundation66 c++]# g++ 多态练习.cpp
[root@foundation66 c++]# ./a.out 
Base constuct//先
Member constuct
Derive constuct
Base destuct//父类指针只会调用父类析构函数

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!