11c++多态

1、多态的基本概念

成员函数加上关键字virtual后Animal里多了个指针vfptr,指向vftable,里边储存了Animal& animal的地址。

如果子类重写成员函数,那么复制过来的vftable会储存重写的类,即储存的是Cat& cat的地址。

#include<iostream>
using namespace std;

class Animal
{
public:
	//地址早绑定  在编译阶段确定函数地址
	//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,也就是地址晚绑定
	virtual void Speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Cat:public Animal
{
public:
	void Speak()
	{
		cout << "小猫在说话" << endl;
	}
};

class Dog:public Animal
{
public:
	void Speak()
	{
		cout << "汪汪汪" << endl;
	}
};

//动态多态满足条件
//1、有继承关系
// 2、子类重写父类的虚函数   
//重写的概念:函数返回值类型 函数名  参数列表  都完全一致称为重写

// 动态多态的使用
//  !!!用父类的指针或者引用 指向子类对象,见41行

void dospeak(Animal& animal) //Animal& animal = cat;
{
	animal.Speak();

}

void test()
{
	Cat cat;
	dospeak(cat);
	Dog dog;
	dospeak(dog);
}
int main()
{
	test();
	return 0;
}

2、动态多态使用的几种方法

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

方法一:父类的引用指向子类对象

特点:这里创建一个对象去调用dospeak的引用参数

class Animal
{
public:
	//地址早绑定  在编译阶段确定函数地址
	//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,也就是地址晚绑定
	virtual void Speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Cat:public Animal
{
public:
	void Speak()
	{
		cout << "小猫在说话" << endl;
	}
};

class Dog:public Animal
{
public:
	void Speak()
	{
		cout << "汪汪汪" << endl;
	}
};
void dospeak(Animal& animal) //Animal& animal = cat;
{
	animal.Speak();

}

void test()
{
	Cat cat; //这里创建一个对象去调用dospeak的引用参数
	dospeak(cat);
	Dog dog;
	dospeak(dog);
}

方法二:父类的指针指向子类对象

特点:用指针的只需要 “new 数据类型  ”就可以,()里为占位参数,可加可不加。

!!用完后记得释放!!


class abstractcalculator
{
public:
	virtual int getresult()
	{
		return 0;
	}
	int m_A;
	int m_B;
};

class Add :public abstractcalculator
{
	virtual int getresult()
	{
		return m_A + m_B;
	}
};

void test()
{
	//多态使用条件
	//父类指针或者引用指向子类对象
	abstractcalculator* abc = new Add();
	abc->m_A = 100;
	abc->m_B = 100;
	cout << abc->m_A << " + " << abc->m_B << " = " << abc->getresult() << endl;
	//用完后记得释放
	delete abc;

   注意:如果拥有多个大同小异相关功能的虚函数时,用另外一个虚函数来包括所有的虚函数。

class abstractDrink
{
public:
	virtual void Boil() = 0;
	virtual void Brew() = 0;
	virtual void Pourincup() = 0;
	virtual void Putsomething() = 0;
	void makeDrink() //用来包括取余虚函数
	{
		Boil();
		Brew();
		Pourincup();
		Putsomething();
	}
};

class Coffee:public abstractDrink
{
public:
	virtual void Boil()
	{
		cout << "加入开水" << endl;
	}
	virtual void Brew() 
	{
		cout << "冲泡咖啡" << endl;
	}
	virtual void Pourincup() 
	{
		cout << "倒入杯中" << endl;
	}
	virtual void Putsomething()
	{
		cout << "加入糖和牛奶" << endl;
	}
};
void dowork(abstractDrink* abs)
{
	abs->makeDrink(); //这个虚函数包括了取余的虚函数
	delete abs; //用完记得释放
}

void test()
{
	dowork(new Coffee);
	dowork(new Tea);
}

3、虚析构函数和纯虚析构函数

#include<iostream>
using namespace std;

class Animal
{
public:
	Animal()
	{
		cout << "Animal的构造函数" << endl;
	}
	//虚析构
	//virtual ~Animal()
	//{
	//	cout << "Animal的析构函数" << endl;
	//}
	
	//!!!注意,纯虚析构函数和虚析构函数只能有一个,有了其之后子类才能执行析构函数——释放堆区数据
	
	//纯虚析构函数的声明
	//!!!有了纯虚析构之后,即使没有纯虚函数,这个类也属于抽象类,无法实例化对象
	virtual ~Animal() = 0;

	//纯虚函数
	virtual void speak() = 0;
};
//纯虚构函数的实现
Animal::~Animal()
{
	cout << "Animal的纯虚析构函数" << endl;
}
class Cat:public Animal
{
public:
	Cat(string name)
	{
		cout << "Cat的构造函数" << endl;
		m_Name = new string(name);
	}

	virtual void speak()
	{
		cout << *m_Name << "小猫在说话" << endl;
	}
	~Cat()
	{
		if (m_Name != NULL)
		{
			delete m_Name;
			m_Name = NULL;
		}
		cout << "Cat的析构函数" << endl;
	}
	string* m_Name;
};

void test()
{
	Animal* a = new Cat("Tom");
	a->speak();
	//父类指针在析构时候,不会调用子类中的析构函数,导致如果子类有堆区属性,出现内存泄露
	//解决方法为虚析构
	delete a;
}
int main()
{
	test();
	return 0;
}

4、组装电脑案例

#include<iostream>
using namespace std;

//创建抽象类
class CPU
{
public:
	virtual void caculate() = 0;
};
//创建抽象类
class Videocard
{
public:
	virtual void show() = 0;
};
//创建抽象类
class Memory
{
public:
	virtual void storage() = 0;
};
创建电脑类
class Computer 
{
public:
	//利用构造函数初始化零件
	Computer(CPU* cpu, Videocard* vc, Memory* me)
	{
		this->cpu = cpu;
		this->me = me;
		this->vc = vc;
	}
	~Computer()
	{
		if (this->cpu != NULL)
		{
			delete this->cpu;
			this->cpu = NULL;
		}
		if (this->vc != NULL)
		{
			delete this->vc;
			this->vc = NULL;
		}
		if (this->me != NULL)
		{
			delete this->me;
			this->me = NULL;
		}
	}
	//提供全部零件工作接口
	void work()
	{
		cpu->caculate();
		vc->show();
		me->storage();
	}

private:
	//因为零件是纯虚函数不能直接创建对象 必须用指针创建 而它们又放在电脑类的构造中 所以要在电脑类中析构内存释放堆区数据
	CPU* cpu;
	Videocard* vc;
	Memory* me;
};

class Intercpu: public CPU
{
public:
	virtual void caculate()
	{
		cout << "英特尔的CPU开始计算了" << endl;
	}

};

class Intervideocard : public Videocard
{
public:
	virtual void show()
	{
		cout << "英特尔的显示器开始显示了" << endl;
	}

};

class Intermemory : public Memory
{
public:
	virtual void storage()
	{
		cout << "英特尔的内存条开始储存了" << endl;
	}

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

};

class Lenovovideocard : public Videocard
{
public:
	virtual void show()
	{
		cout << "Lenovo的显示器开始显示了" << endl;
	}

};

class Lenovomemory : public Memory
{
public:
	virtual void storage()
	{
		cout << "Lenovo的内存条开始储存了" << endl;
	}

};
void test()
{
	CPU* intercpu = new Intercpu;
	
	Videocard* vc = new Intervideocard;
	
	Memory* me = new Intermemory;

	Computer* c1 = new Computer(intercpu, vc, me);
	c1->work();
	delete c1;
	cout << "--------------------------" << endl;
	cout << "第二台电脑" << endl;
	Computer* c2 = new Computer(new Lenovocpu, new Lenovovideocard, new Lenovomemory);
	c2->work();
	delete c2;
	cout << "--------------------------" << endl;
	cout << "第三台电脑" << endl;
	Computer* c3 = new Computer(new Intercpu, new Lenovovideocard, new Intermemory);
	c3->work();
	delete c3;
}
int main()
{
	test();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值