C++多态详解

目录

一、多态的概念

二、多态的定义及实现

1.多态的构成条件 

 2.虚函数

3.虚函数的重写 

4.例题理解(超级重要,强烈建议做一下)

 5.C++11 override和 final

6.重载、覆盖(重写)、隐藏(重定义)的对比

三、抽象类

1.概念 

2.接口继承与实现继承

四、多态的原理

1.虚函数表 

2.原理

3.静态绑定与动态绑定

 五、单继承和多继承关系的虚函数表

1.单继承中的虚函数表

 2.多继承中的虚函数表

l六、一些经典的面试问题


一、多态的概念

多态用通俗的话来说就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。

举个栗子:买票

普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。

二、多态的定义及实现

1.多态的构成条件 

首先,多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。

比如Student继承了 Person。Person对象买票全价,Student对象买票半价。

在继承中构成多态有两个条件:

1.必须通过基类的指针和引用调用虚函数

2.被调用的函数必须是虚函数 ,且派生类必须对基类的虚函数进行重写

例:

class Person
{
	public:
		virtual void BuyTicket()
		{ 
			cout << "买票-全价" << endl;
		}
};

	
class Student : public Person
{
public:
	virtual void BuyTicket()
	{ 
		cout << "买票-半价" << endl;
	}
};
	
// 多态
// 条件1:虚函数的重写 -> 父子类中两个虚函数,三同(函数名、参数、返回)
// 条件2:父类指针或引用去调用虚函数
void Func(Person& p)
{
	p.BuyTicket();
}
	
int main()
{
	Person ps;
	Student st;
	
	Func(ps);
	Func(st);
	
	return 0;
}

 2.虚函数

被virtual修饰的类成员函数称为虚函数

class Person
{
	public:
		virtual void BuyTicket()
		{ 
			cout << "买票-全价" << endl;
		}
};

3.虚函数的重写 

虚函数的重写(或者覆盖):派生类中有一个跟基类完全相同的虚函数(返回类型、函数名、参数列表完全相同),则称子类的虚函数重写了基类的虚函数

class Person
{
	public:
		virtual void BuyTicket()
		{ 
			cout << "买票-全价" << endl;
		}
};

	
class Student : public Person
{
public:
	virtual void BuyTicket()
	{ 
		cout << "买票-半价" << endl;
	}
};

注:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用

虚函数重写的两个特殊:

1.协变(基类与派生类虚函数返回值类型不同)

即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变

class A
{};

class B : public A
{};

class Person
{
public:
	virtual A* f()
	{ 
		return new A;
	}
};

class Student : public Person
{
public:
	virtual B* f()
	{ 
		return new B;
	}
};

2.析构函数的重写(基类与派生类析构函数的名字不同)

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字, 都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。

虽然函数名不相同, 看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor。

class Person
{
public:
	virtual ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person
{
public:
	virtual ~Student() { cout << "~Student()" << endl; }
};
// 只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
//数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{
	Person* p1 = new Person;
	Person* p2 = new Student;
	delete p1;
	delete p2;
	return 0;
}

4.例题理解(超级重要,强烈建议做一下)

class A
{
public:
	virtual void func(int val = 1) 
	{ 
		std::cout << "A->" << val << std::endl;
	}
	
	virtual void test() { func(); }
};
	
class B : public A
{
public:
	void func(int val = 0) { std::cout << "B->" << val << std::endl; }
};
	
int main(int argc, char* argv[])
{
	B* p = new B;
	p->test();

	return 0;
}

A:A->0   

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饿了我会自己捡代码吃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值