C++之多态

1、定义

多态通俗来说就是多种形态,即目标去实现某一行为,当对象不同时会产生不同状态

2、多态构成条件

(1)继承关系父子的两个虚函数,要保证三同(函数名/参数/返回值)。

(2)必须通过基类的指针或者引用调用虚函数(修饰词virtual,只能修饰成员函数)。

(3)被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写。

破坏上面条件可能会造成普通函数调用,而不是多态调用。

class A
{
public:
	virtual void f()//vitual修饰虚函数
	{
		cout << "A::f()" << endl;
	}
};
class B : public A
{
public:
	 void f()//派生类实现虚函数重写即覆盖,派生类可以省略修饰词virtual
	{
		cout <<  "B::f()" << endl;
	}
};
void func(A& a) {
	a.f();
}
int main() {
	A a;
	B b;
	func(b);//对象a调用则输出A::f(),b调用则输出B::f()
	return 0;
}

3、虚函数重写的两种特殊形式

(1)协变

基类和派生类虚函数的返回值类型不同,基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用。

class Person {
public:
	virtual A* f() { 
		cout << "Person::f()" << endl; 
		return new A;
	}
};
class Student : public Person {
public:
	virtual B* f() { 
		cout << "Student::f()" << endl;
		return new B; 
	}
};

(2)析构函数的重写

因为基类与派生类的析构函数的名字不同,因此编译器对析构函数的名称多了特殊处理,编译后析构函数的名称统一处理成destructor。如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写。如果不考虑下面这种情况会出现内存泄漏问题。

class A
{
public:
	virtual ~A() {
		cout << "~A()" << endl;
	}
};
class B : public A
{
public:
	 ~B() {
		cout << "~B()" << endl;
	}
};
int main() {
	A* a = new A;
	delete a;

	a = new B;
	delete a;
	//这里希望释放的是对象B,遵循先释放基类再释放派生类的原则
	//如果不加虚函数则只会释放基类,因为这里对象本身是A类型,赋值只是截取
	return 0;
}

4、两个特殊修饰词

(1)final

该修饰词用于处理不允许重写的函数,基类中一经final修饰,则派生类中无法重写该函数。

class A
{
public:
	virtual void func() final {

	}
};

(2)override

该修饰词用于检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译会报错。

class B : public A
{
public:
	virtual void func()  override {

	}
};

5、重载、重写、隐藏的区别

重载重写(覆盖)隐藏(重定义)
作用域两个函数必须在同一作用域一个函数在基类,一个函数在派生类一个函数在基类,一个函数在派生类
函数名相同相同相同
参数不同相同无要求
返回值相同相同(协变除外)无要求

6、抽象类

纯虚函数是在虚函数后面写上=0,包含纯虚函数的类称为抽象类(也可称为接口类),抽象类不能实例化出对象。只有重写纯虚函数之后,派生类才能实例化出对象。

class A
{
public:
	virtual void func() = 0;//纯虚函数的定义
};
class B : public A
{
public:
	virtual void func(){//重写
		 cout << "B-用来吃饭" << endl;
	}
};
class C : public A
{
public:
	virtual void func() {//重写
		cout << "C-用来喝水" << endl;
	}
};
int main() {
	B b;
	C c;
	A& a = b;
	A& aa = c;
	a.func();//引用调用基类
	aa.func();
	return 0;
}

输出结果:

注意:虚函数的继承是一种接口继承,派生类继承的是虚函数的接口,目的就是为了重写重写的是函数实现方法,函数中的缺省参数值不会重写。而普通函数的继承,继承的是函数实现方法。另外如果不实现多态,建议不要把函数定义成虚函数。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值