C++继承、多态,虚成员函数(包括虚析构函数、虚复制构造函数)学习笔记

通过哺乳类派生猫、狗等学习继承、多态中的知识点

先贴上类的代码

#include<iostream>

enum BREED { YORKIE, CAIRN, DANDIE, SHETLAND, DOBERAMN, LAB };//犬种

class Mammal {
public:
	Mammal() :age(2), weight(5) {}
	//~Mammal() { std::cout << "Mamal 销毁" << std::endl; }//析构函数

	//如果基类Mammal没有声明虚析构函数,释放派生类时将不能调用派生类的析构函数
	virtual~Mammal() { std::cout << "Mamal 销毁" << std::endl; }//虚析构函数

	//虚复制构造函数
	//通过基类指针创建一个派生类对象的拷贝 
	virtual Mammal* clone() { return new Mammal(*this); }

	int getAge()const { return age; }
	void setAge(int newAge) { age = newAge; }
	int getWeight()const { return weight; }
	void setWeight(int newWeight) { weight = newWeight; }

	//void speak() { std::cout << "Mamal Sound!" << std::endl; }
	virtual void speak()const { std::cout << "Mamal Sound!" << std::endl; }//虚函数

	void move()const { std::cout << "Mamal moving..." << std::endl; }
	void sleep() { std::cout << "Mamal Sleeping!" << std::endl; }

protected:
	int age;
	int weight;

};

class Dog :public Mammal {
public:
	Dog() :itsBreed(YORKIE) {}
	~Dog() { std::cout << "Dog 销毁" << std::endl; }

	//虚复制构造函数
	//通过基类指针创建一个派生类对象的拷贝
	virtual Mammal* clone() { return new Dog(*this); }

	BREED getBreed()const { return itsBreed; }
	void setBreed(BREED newBreed) { itsBreed = newBreed; }

	void speak()const { std::cout << "Woof!..." << std::endl; }

	void move()const { std::cout << "Dog moving..." << std::endl; }

	void wagTail() { std::cout << "Tail wagging..." << std::endl; }
	void begForFood() { std::cout << "Begging for food..." << std::endl; }

protected:
	BREED itsBreed;
};

//以下是简化类
class Cat :public Mammal {
public:
	~Cat() { std::cout << "Cat 销毁" << std::endl; }

	//虚复制构造函数
	//通过基类指针创建一个派生类对象的拷贝
	virtual Mammal* clone() { return new Cat(*this); }

	void speak()const { std::cout << "Meow!..." << std::endl; }

	void purr()const { std::cout << "Rrrrrrrrrrrrr..." << std::endl; }//Cat特有的方法
};

class Horse :public Mammal {
public:
	~Horse() { std::cout << "Horse 销毁" << std::endl; }

	//如果没有定义虚复制构造函数,将调用基类Mammal的方法,因为派生的Horse部分没有复制过来
	virtual Mammal* clone() { return new Horse(*this); }

	void speak()const { std::cout << "Whinny!..." << std::endl; }
};

class Pig :public Mammal {
public:
	~Pig() { std::cout << "Pig 销毁" << std::endl; }

	virtual Mammal* clone() { return new Pig(*this); }

	void speak()const { std::cout << "Oink!..." << std::endl; }
};

主程序

#include <iostream>
#include <string>
#include "mammal.h"

//调用speak方法
void valuefuction(Mammal mammalvalue);//切除,speak调用Mammal版本
void ptrfuction(Mammal *mammalvalue);
void reffuction(Mammal &mammalvalue);

int main()
{
	Mammal *pDog = new Dog;
	pDog->speak();//pDog是Mammal对象,但是speak是虚成员函数,调用Dog中的方法
	pDog->move();//pDog是Mammal对象,调用Mammal中的方法//dog没有此方法

	std::cout << "+++++++++++++++++++++++++Mammal指针数组+++++++++++++++++++++++++" << std::endl;
	Mammal *array[5] = { new Dog,new Cat,new Horse,new Pig,new Mammal };
	for (int i = 0; i < 5; i++) {
		//array[i]->speak();
		(*array[i]).speak();//先解析再调用方法,与上一句同义

		delete[]array[i]; //释放指针数组需迭代?
	}

	//delete[]array;//错误,释放指针数组需迭代?

	std::cout << "+++++++++++++++++++++++++Mammal切除+++++++++++++++++++++++++" << std::endl;
	//调用speak方法
	Mammal *ptr = new Dog;
	valuefuction(*ptr);//切除,speak调用Mammal版本,因为参数为Mammal对象
	ptrfuction(ptr);
	reffuction(*ptr);
	ptr = new Cat;
	valuefuction(*ptr);//切除,speak调用Mammal版本,因为参数为Mammal对象
	ptrfuction(ptr);
	reffuction(*ptr);

	std::cout << "++++++验证虚析构函数++++++++++" << std::endl;
	Mammal *Animal = new Mammal;
	Dog *pDog55 = new Dog;
	Mammal *horse = new Horse;
	delete horse;//如果基类Mammal没有声明虚析构函数,将不能调用Horse的析构函数
				 //可以通过注释Horse类中的虚析构函数验证
	delete Animal;
	delete pDog55;
	std::cout << "++++++验证虚析构函数+++++++++++++" << std::endl;

	std::cout << "++++++验证虚复制构造函数+++++++++++++" << std::endl;
	Mammal *dog1 = new Dog;
	Mammal *horse1 = new Horse;
	dog1->speak();
	horse1->speak();

	Mammal *dog2 = dog1->clone();
	Mammal *horse2 = (*horse1).clone();
	dog2->speak();//Dog类定义了虚复制构造函数,可以正确调用Dog类的speak方法
	horse2->speak();//Horse类如果没有定义虚复制构造函数,将调用基类Mammal的方法,因为派生的Horse部分没有复制过来
					//注释虚复制函数得到不同结果
	std::cout << "++++++验证虚复制构造函数+++++++++++++" << std::endl;

	std::cout << "++++++验证dynamic_cast转换 通过基类指针访问派生类特定函数+++++++++++" << std::endl;
	Mammal *cat1 = new Cat;
	cat1->speak();
	Cat* pcat = dynamic_cast<Cat*>(cat1);
	//cat1->purr();//错误,应该使用转换得到的新指针调用
	pcat->purr();


	return 0;
}

void valuefuction(Mammal mammalvalue)
{
	mammalvalue.speak();
}

void ptrfuction(Mammal * mammalvalue)
{
	mammalvalue->speak();
}

void reffuction(Mammal & mammalvalue)
{
	mammalvalue.speak();
}

笔记:

虚复制构造函数

通过基类指针创建一个派生类对象的拷贝

基类指针指向派生类对象,怎样用基类指针创建一个新的派生类对象?

虚析构函数:当且仅当类里包含至少一个虚函数的时候才去声明虚析构函数。

如果释放派生类时,基类没有声明虚析构函数,将不能调用派生类的析构函数

基类指针不能访问派生类特有的成员函数,可用dynamic_cast转换符运算符把基类指针转换为派生类指针,如果转换失败指针为空

抽象类与具体类比较
1.抽象类不能直接实例化
2.抽象类可以不含抽象方法
3.抽象类中含有抽象方法时,如果子类继承该抽象类,则必须重写该抽象方法
4.抽象类可以有非抽象方法
5.允许(但不要求)抽象类包含抽象成员。
6.抽象类不能被密封。
7.抽象类含有非抽象方法,而且子类继承该类时,重写了该方法,那么该子类的对象调用该方法时,是子类中的方法;如果子类没有重写该父类中的非抽象方法,那么子类对象调用的是父类中的方法。

猜你喜欢

转载自blog.csdn.net/holyweng/article/details/80845474