Visual C++ 2008入门经典 第九章类的继承和虚函数

// 第九章类的继承和虚函数
//.cpp: 主项目文件。
//1 继承如何与面向对像的编程思想适应
//2 根据现有类定义新类
//3 使用protected关键字为类成员指定新的访问特性
//4 如何使某个类成为另一个类的友元
//5 虚函数及其使用方法
//6 纯虚函数
//7 抽像类
//8 虚析构函数的概念,何时时使用虚析构函数


//9.2 类的继承
//派生类不继承的基类成员仅有析构函数,构造函数以及任何重载赋值运算符的成员函数
//9.2.1 基类的概念

#include "stdafx.h"
#include 
using namespace std;
using namespace System;
//9.2.2 基类的派生类
/*class CBox
{
public:
	double m_Length;
	double m_Width;
	double m_Height;
	CBox(double lv = 1.0,double wv =1.0, double hv = 1.0)
		:m_Length(lv), m_Width(wv), m_Height(hv)
	{ }
};

//定义CCandBox
class CCandBox: public CBox
{
public:
	char* m_Contents;
	int count;
	CCandBox(char* str = "Candy")
	{
	     m_Contents = new char[strlen(str) +1];
		 strcpy_s(m_Contents, strlen(str)+1, str);
		 //strcpy_s三个参数,复制操作目标,目标缓冲区的长度和数据原
		 //如果两个数组都是静态的,即都不在堆上分配的,那么我们可以省略第二个实参,而只提供目标和数据扰的指针
		 //这样做是可以的,因为strcpy_s()函数还可以用作能够自动推断目标字符串长度的模板函数,因此
		 //当我们处理静态字符串时,调用该函数只提供目标少源字符串作为参数即可
	}
	~CCandBox()
	{
	   delete []m_Contents;
	}
};
int main(array ^args)
{
    CBox myBox(4.0, 3.0, 2.0);
	CCandBox myCandyBox;
	CCandBox myMintBox("Wafet Thin Mints");
	cout< ^args)
{
    CBox myBox(4.0, 3.0, 2.0);
	CCandBox myCandyBox;
	CCandBox myMintBox(1.0, 2.0, 3.0, "Wafet Thin Mints");
	cout< ^args)
{
    CBox myBox(4.0, 3.0, 2.0);
	CCandBox myCandyBox;
	CCandBox myMintBox(1.0, 2.0, 3.0, "Wafet Thin Mints");
	cout< ^args)
{
    CBox myBox(4.0, 3.0, 2.0);
	CCandBox myCandyBox;
	CCandBox myMintBox(1.0, 2.0, 3.0, "Wafet Thin Mints");
	cout<
using namespace std;
using namespace System;
//start 类的友元成员/////////////////////////////////////////////////
class F1;
class F2
{
private:
	int var2;
public:
	int copy(F1* f1); //在F2中声明一个函数,叁数为接收F1的地址
	F2(F1* f1) //构造函数的参数为F1的地址
	{
	    var2 = copy(f1); //这里F2的构造函数不能直接访问f1的私有成员,只有通过copy这个友元函数来完成
	}

	int GetVar()
	{
	    return var2;
	}
};
class F1
{
private:
	int var;
	friend int F2::copy(F1* f1);
public:
	F1(){
	   var = 250;
	}
};
//最后来定义一个F2::copy()函数
int F2::copy(F1* f1)
{
     return f1->var;
}
//end 类的友元成员/////////////////////////////////////////////////



//下面用来定义一打瓶子的包装箱
class CBottle;
class CCarton
{
public:
	CCarton(const CBottle& aBottle);
	double Volume()
	{
		 cout<<"m_Height:"< ^args)
{
	//这里只是实现类的友元成员,并不是类的友元类
	F1 f1;
	F2 f2(&f1);
	cout<<"var2:"<
using namespace std;
using namespace System;
class CBox
{
public:
	void ShowVolume()
	{
	   cout<<"CBox usable volume is "< ^args)
{
	CBox myBox(2.0, 3.0, 4.0);
	CGlassBox myCGlassBox(2.0, 3.0, 4.0);
	myBox.ShowVolume();
	myCGlassBox.ShowVolume();
	//我们希望在程序执行时再解决特定的对像实例中使用哪里个Volume()函数的问题,这种操作被称为动态连接或后期绑定
	//我们希望ShowVolume()实际调用的Volume()函数版本由被处理的对像种类确定,而不是程序执行之前由编译器任意确定
	//我们需要使用的是虚函数
	system("pause");
    return 0;
}*/


//9.6.1 虚函数
//虚函数是以vritual关键字声明的基类函数,如果有基类中将某个函数指定为virtual,并且派生类中有另外一个该函数的定义
//则编译器将知道我们不想静态连接该函数,我们真正需要的是基于调用该函数的对像种类,在程序的特定位置选择调用哪一个函数
/*#include "stdafx.h"
#include 
using namespace std;
using namespace System;
class CBox
{
public:
	void ShowVolume()
	{
	   cout<<"CBox usable volume is "< ^args)
{
	CBox myBox(2.0, 3.0, 4.0);
	CGlassBox myCGlassBox(2.0, 3.0, 4.0);
	myBox.ShowVolume();
	myCGlassBox.ShowVolume();
	
	system("pause");
    return 0;
}*/
//要使用某个函数的表现出虚函数的行为,该函数在任何派生类中都必须有与基类函数相同的名称,形参数和返回类型,如果基类是const,
//那么派生类中的函数也必须是const,如果我们企图使用不同形参或返回类型,或者将一个声明为const,而另一个不然,由虚函数机制将不能工作
//注意:
//从派生类函数观点来看,CGlassBox派生类中的Volume()函数实际上隐藏了该函数的基类版本
//如果我们希望从某个派生类函数中调用基类的Volume()函数,由需要以CBox::Volume()这样的形式使用作用域解析运算符来引用基类函数



//9.6.2 使用指向类对像的指针
//使用指针处理基类和派生类的对像是一项重要的技术,指向基类对像的指针不仅可以包含基类对像的地址,还可以包含派生类对像的地址
//因此,我们可以根据被指向的对像种类,使用类型为"基类指针"的指针获得虚函数的不同行为
/*#include "stdafx.h"
#include 
using namespace std;
using namespace System;
class CBox
{
public:
	void ShowVolume()
	{
	   cout<<"CBox usable volume is "< ^args)
{
	CBox* pCbox;
    CBox myBox(2.0, 3.0, 4.0);
	pCbox = &myBox;
	cout<<"myBox.Volume:";
	pCbox->ShowVolume();

    CGlassBox myCGlassBox(2.0, 3.0, 4.0);
	pCbox = &myCGlassBox;
	cout<<"CGlassBox.Volume:";
	pCbox->ShowVolume();
	//结论:虚函数机制借助于指向基类的指针同样能够正常工作,实际调用的函数是基于被指向的对像类型而选择的
	//这意味着即使我们不知道程序中某个基类指针所指对像的准确类型(比如某个指针作为实参传递给函数时)
	//虚函数机制也能确保调用正确的函数,这是一种特别强在的功能,因此务必充分理解
    system("pause");
    return 0;
}*/

//9.6.3 使用引用处理虚函数
//如果我们定义一个形参为基类引用的函数,由可以给该函数传递派生类的对像作为实参,该函数在执行的时候,将自动为传递进来的对像选择造当的虚函数
/*#include "stdafx.h"
#include 
using namespace std;
using namespace System;
class CBox
{
public:
	void ShowVolume()
	{
	   cout<<"CBox usable volume is "< ^args)
{
	CBox myBox(2.0,3.0,4.0);
	CGlassBox myGlassBox(2.0,3.0,4.0);
	Output(myBox);
	Output(myGlassBox);
	system("pause");
    return 0;
}
//class CBox;
//该语句只是将名称CBox标识为此该还没有被定义的类,但已经足以使编译器知道CBox是个类名,同时使编译器能够了处理Output()函数的原型,
//如果不指出CBox是一个类,那么Output()的原型声明将导致编译器生成一条出错消息
void Output(CBox& aBox)
{
	  aBox.ShowVolume();
}
*/

//9.6.4 纯虚函数
/*#include "stdafx.h"
#include 
using namespace std;
using namespace System;
const double PI = 3.14159265;
//定义纯虚函数
class CContainer
{
public:
	virtual double Volume() const = 0;
	//定义虚函数Volume()的语句通过在函数头中添加等号和0,将该函数定义成没有任何内容,这样的函数被称为纯虚函数

	virtual void ShowVolume() const
	{
	   cout< ^args)
{
	CContainer* pC1 = new CBox(2.0,3.0, 4.0);

	CContainer* pC2 = new CCan(6.5, 3.0);

	pC1->ShowVolume();
	pC2->ShowVolume();
	delete pC1;
	delete pC2;
	//由于派生类对像是动态创建的,因此我们不需要它们时必须使用delete运算符清理自由存储器
	system("pause");
    return 0;
}*/



//9.6.6 间接基类 子类的基类可以是多另外一个基类派生出来的
/*#include "stdafx.h"
#include 
using namespace std;
using namespace System;
const double PI = 3.14159265;
//定义纯虚函数
class CContainer
{
public:
	virtual double Volume() const = 0;
	//定义虚函数Volume()的语句通过在函数头中添加等号和0,将该函数定义成没有任何内容,这样的函数被称为纯虚函数

	virtual void ShowVolume() const
	{
	   cout< ^args)
{
	CContainer* pC1 = new CBox(2.0,3.0, 4.0);
	
	CCan myCan(6.5, 3.0);
	CGlassBox myGlassBox(2.0, 3.0, 4.0);
	pC1->ShowVolume();
	delete pC1;

	pC1 = &myCan;
	pC1->ShowVolume();

	pC1 = &myGlassBox;
	pC1->ShowVolume();
	//delete pC1; //这里为什么最后不delete pC1了
	//是因为程序一运行结束,动态内存也就自动释放了吗???
	cout<

  

你可能感兴趣的:(Visual C++ 2008入门经典 第九章类的继承和虚函数)