C++面向对象的多态性、纯虚函数、空类的大小——C++学习记录04

C++面向对象之多态性

1.静态多态

通过函数重载和运算符重载实现,在编译时确定函数早绑定

2.动态多态

派生类和虚函数实现运行时多态,运行阶段实现函数晚绑定。

当子类重写了父类的虚函数时,子类中的虚函数表将替换父类中的虚函数,

所以当父类的引用或者指针指向子类对象时,将发生多态

3.多态的好处

结构清晰

可读性很强

利于后期的拓展和维护

3.1使用方法

父类的引用或者指针指向子类的对象

4.纯虚函数

定义格式:virtual 返回值类型 函数名称(参数列表) = 0;

类中有了纯虚函数,称为抽象类,抽象类无法实例化对象

子类必须重写父类中的所有纯虚函数,才能实例化对象,否则也是抽象类

5.虚析构与纯虚析构

5.1问题

多态使用时,如果子类中有属性开辟到了堆区,则父类指针释放时无法调用子类的析构函数

5.2解决

将父类中的析构函数改为虚析构函数或者纯虚析构函数

纯虚析构函数需要先声明,后实现,但是纯虚函数可以只声明

如果子类没有堆区数据,可以不将父类的析构函数写成虚析构或者纯虚析构

拥有纯虚析构函数的类也属于抽象类

6.空类的大小

空类(即里面什么代码都没有)的大小通过sizeof测定的结果是1

vfptr(虚函数表指针) ——> vftable(虚函数表,用于记录虚函数的地址)

7.代码

#include<iostream>

using namespace std;

class Animal {
public:
	Animal() {
		cout << "基类中的构造函数被调用!" << endl;
	}

	// 虚函数,虚函数将实现晚绑定
    virtual void speack() {
		cout << "动物在说话!" << endl;
	}
	virtual ~Animal() = 0;			// 纯虚析构函数,纯虚析构声明后,必须定义
};


// Animal中的纯虚析构实现部分,可以在这里释放父类开辟的堆空间
Animal::~Animal() {}

class Cat :public Animal {

public:
	Cat() {
		cout << "cat中的构造函数被调用" << endl;

	}
	void speack() {
	
		cout << "小猫在说话!" << endl;
	}
	~Cat() {

		cout << "cat中的析构函数被调用" << endl;
	}
};

class Dog : public Animal {
public:
	void speack() {
		cout << "小狗在说话" << endl;
	}
	~Dog() {
		cout << "dog中的析构函数被调用" << endl;
	}
};

// 地址早绑定,在编译阶段函数地址已经早绑定Animal
void doSpeack(Animal& animal) {
	animal.speack();
}

// 派生类重写基类中的虚函数,当基类的引用或者指针指向派生类时,实现多态
void test01() {
	Cat cat;
	Dog dog;

	doSpeack(cat);
	doSpeack(dog);

}

// 基类和派生类的构造函数和析构函数的调用
// 
void test02() {

	Animal* p_cat = new Cat();			// 开辟内存到堆区,需要手动释放
	if (p_cat != NULL) {
		delete p_cat;						// 释放指针
		p_cat = NULL;

	}
	
}
	
// --------------------------------------------------------------------------
class CPU {
public:
	virtual void caculate() = 0;
};

class VideoCard {
public:
	virtual void display() = 0;
};

class Memory {
public:
	virtual void storage() = 0;
};

class Computer {
public:
	Computer(CPU *cpu, VideoCard *videoCard,Memory * memory) {
		this -> m_cpu = cpu;
		this -> m_vc = videoCard;
		this -> m_mem = memory;
	}

	// 电脑的工作
	void work() {
		m_cpu->caculate();
		m_vc->display();
		m_mem->storage();

	}
	~Computer() {
		if (m_cpu != NULL) {
			delete m_cpu;
		}
		if (m_vc != NULL) {
			delete m_vc;
		}if (m_mem != NULL) {
			delete m_mem;
		}
	}

private:
	CPU* m_cpu;
	VideoCard* m_vc;
	Memory* m_mem;
};
// inter厂商
class InterCPU :public CPU {

public:
	 void caculate() {
		cout << "inter的CPU开始计算了" << endl;
	
	}
};

class InterVideoCard :public VideoCard {

public:
	 void display() {
		cout << "inter的显卡开始计算了" << endl;

	}
};
class InterMemory :public Memory {

public:
	 void storage() {
		cout << "inter的内存条开始存储了" << endl;

	}
};
// lenovo

class lenovoCPU :public CPU {

public:
	virtual void caculate() {
		cout << "lenovo的CPU开始计算了" << endl;

	}
};

class lenovoVideoCard :public VideoCard {

public:
	virtual void display() {
		cout << "lenovo的显卡开始计算了" << endl;

	}
};
class lenovoMemory :public Memory {

public:
	virtual void storage() {
		cout << "lenovo的内存条开始存储了" << endl;

	}
};

void test03() {

	// 创建电脑
	CPU* interCPU = new InterCPU;
	VideoCard* interCard = new InterVideoCard;
	Memory* interMemory = new InterMemory;

	Computer* computer1 = new Computer(interCPU, interCard, interMemory);
	computer1->work();
	delete computer1;

	cout << "---------------------------" << endl;
	Computer* computer2 = new Computer(new lenovoCPU, new lenovoVideoCard,new lenovoMemory);
	computer2->work();
	delete computer2;

	cout << "---------------------------" << endl;
	Computer* computer3 = new Computer(new InterCPU, new lenovoVideoCard, new lenovoMemory);
	computer3->work();
	delete computer3;
}
int main() {   

	//test01();
	//test02();
	test03();
	system("pause");
	return 0;
}

8.测试结果

8.1父类中无虚函数,父类的指针指向子类对象,将调用父类中的函数,无法调用子类中的重写函数,即无法实现多态

在这里插入图片描述

8.2父类中的函数由虚函数实现

在这里插入图片描述

父类的指针指向小猫子类,将调用小猫类中的重写函数,实现多态

8.3父类指针对象,无法释放子类中开辟的堆空间数据

在这里插入图片描述

cat类中的析构函数没有被调用,无法释放开辟的堆空间数据

8.4将父类的析构函数定义为虚析构函数

子类中的析构函数被调用
在这里插入图片描述

8.5将父类中的析构函数定义为纯虚析构函数

子类中的析构函数被调用,将父类中的析构函数声明为纯虚析构函数后,必须要实现声明的函数。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值