C++多态的实现(课堂笔记)

1.虚函数实现多态
//虚函数:
//当虚函数的声明和定义分离时时候,声名一定要加 virtual ,但定义不需要加 virtual


//多态
//不同对象做同一件事,多种形态,结果不一样
/*
#include<iostream>
using namespace std;

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

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

// 多态:指向谁,调用谁的虚函数

// 多态的实现:
// 1、父子类完成虚函数重写(三同:函数名、参数、返回值)
//    (父类函数加 virtual 修饰,子类可以不加,但建议加上)
// 2、父类的指针或者引用 去调用虚函数
void Func(Person* p)
{
	p->BuyTicket();//指针调用虚函数
	// p.BuyTicket() 寄,没有多态
}
int main()
{
	Person ps;
	Student st;

	Func(&ps);
	Func(&st);

	return 0;
}

2.协变
//协变: 1.基类与派生类虚函数的 返回值类型 不同
//		  但 返回值是父子类指针关系的引用
//      2.析构函数的重写

/*
#include<iostream>
using namespace std;
class A {};
class B : public A {};

class Person {
public:
	virtual A* BuyTicket()
	//virtual Person* BuyTicket()
	{
		cout << "Person->买票-全价" << endl;
		return nullptr;
	}
	virtual ~Person()
	{
		cout << "~Person()" << endl;
	}
};

class Student : public Person {
public:
	virtual B* BuyTicket() //返回值不同构成协变(返回值一定是父子类指针)
	//virtual Student* BuyTicket()
	//~Student() 子类重写虚函数 可以不加 virtual ,效果一样
	{ 
		cout << "Student->买票-半价" << endl; 
		return 0;
	}
	virtual ~Student()//析构函数的函数名相同,构成重写
	{     
		cout << "delete[]" << _ptr << endl;
		delete[] _ptr;
		cout << "~Student()" << endl;
	}
private:
	int* _ptr = new int[10];

};

void Func(Person* p)
{
	p->BuyTicket();
}
int main()
{
	//Person ps;// ~Peron()
	//Student st;// ~Student()  ~Peron()   析构; 先子后父

	// !!!!!!!!!!重点!!!!!!!!!!!!!
	Person* p1 = new Person;
	Person* p2 = new Student;

	// 析构函数 + operator delete(p1)
	delete p1;// ~Person() 父类析构
	delete p2;// ~Student()
	// delete[]010EFAB8  ~Student()  ~Person()  子类析构+父类析构
	// 结论:  建议析构函数定义为虚函数,防止发生 内存泄漏
	// 不加虚函数析构:  ~Person()   ~Person() 调用两次析构, 子类空间未释放
	return 0;
}
3.多态的底层
#include<iostream>
using namespace std;
class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }

private:
	int _i = 1;
};

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

	int _j = 2;
};

void Func(Person* p)
{
	p->BuyTicket();
}

int main()
{
	Person Mike;
	Func(&Mike);

	Person p1;
	Func(&p1);
	//同一类型的虚表是一样的

	Student Johnson;
	Func(&Johnson);
	//若满足多态,系统就去指向对象的虚表中找对应的虚函数调用

	return 0;
}

4.抽象类

// 多态调用: 运行时,到指向对象的虚表中找虚函数调用,指向父类调用父类的虚函数 ,指向子类调用子类的虚函数
// 普通调用: 编译时,根据调用对象类型,去调用它的函数

// 虚表中存的仅仅是虚函数的地址
// 虚表存放在 常量区 !!!!!!
// 同类型对象共用同一个虚表

/*
#include<iostream>
using namespace std;

//抽象类: (类中至少有一个纯虚函数)
// 1.不能实例化对象(但能使用指针)
// 2.间接强制 子类 重写 虚函数
// 3,不能作为 函数返回值、函数参数
class Car
{
public:
	//纯虚函数 ( 虚函数后加 =0)
	virtual void Drive() = 0;
};

class Benz :public Car// 继承抽象类 也是 抽象类
{
public:
	//纯虚函数被继承
};

class BMW :public Car
{
public:
	virtual void Drive()
	// 完成纯虚函数重写  
	{
		cout << "BMW-Drive()" << endl;
	}
};
int main()
{
	// Car c;    //error
	//Benz b;    //error
	BMW B;

	Car* ptr = &B;// 使用父类指针调用函数,实现多态
	ptr->Drive();
	return 0;
}
例题: 构造顺序
#include<iostream>
using namespace std;

class A {
public:
	A(const char* s) 
	{ cout << s << endl; }
	~A() {}
};

class B :virtual public A
{
public:
	B(const char* s1, const char* s2) 
		:A(s1) 
	{ cout << s2 << endl; }
};

class C :virtual public A
{
public:
	C(const char* s1, const char* s2) 
		:A(s1) 
	{ cout << s2 << endl; }
};

class D :public B, public C
{
public:
	D(const char* s1, const char* s2, const char* s3, const char* s4)
		:B(s1, s2)  //A  B
		, C(s1, s3)  //A  C
		, A(s1)      //A   (A 会在 此处 构造)
		// A 只会被初始化 一次,菱形虚拟继承只有 一个 A
		// !!!!!!!!!!!!!!!!
		// 初始化列表 的 初始化顺序 按照 成员声名的顺序 ,而不是 出现的顺序
		//所以构造顺序 A B C D

	{ cout << s4 << endl;}
};
int main()
{
	D* p = new D("class A", "class B", "class C", "class D");
	// class A, class B, class C, class D
	delete p;

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值