////////////////////////////////////////////////////////////////////////////////
//9.6.7 虚析构函数
/*#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();
cout<ShowVolume();
cout<ShowVolume();
pC1 = &myGlassBox;
pC1->ShowVolume();
//delete pC1; //这里为什么最后不delete pC1了
//是因为程序一运行结束,动态内存也就自动释放了吗???
//delete pC1;
cout<
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* pContainer = new CGlassBox(2.0, 3.0, 4.0); //定义一个基类指针
pContainer->ShowVolume();
CBox* pBox = dynamic_cast(pContainer); //将基类指针强制转换为类层次结构中的CBox*类型
pBox->ShowVolume();
CGlassBox* pGlassBox = dynamic_cast(pContainer);
//转换为实际的类型CGlassBox*
pGlassBox->ShowVolume();
//由于派生类对像是动态创建的,因此我们不需要它们时必须使用delete运算符清理自由存储器
system("pause");
return 0;
}*/
//9.8 嵌套类
//嵌套类可以自由访问封装类的所有静态成员,通过封装类的对像或指向封装类对像的指针或引用,还可以访问所有实例成员
//封装类只能访问嵌套类的公有成员,但在封类所有私有的嵌套类中,类成员通常被声明为public,以使封装类的函数能够自由访问整个嵌套类
/*
#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<pBox; //取得当前头指针所指向的pBox对像,放入到pBox中去
CItem * pTemp = pTop; //将当前的头指针记录下来,放到pTemp中
pTop = pTop->pNext; //将头指针向下移动一位
delete pTemp; //删除记录的老的头指针
return pBox; //返回pBox对像
}
};
int main(array ^args)
{
CBox* pBoxes[] = { new CBox(2.0, 3.0, 4.0),
new CGlassBox(2.0,3.0,4.0),
new CBox(4.0,5.0,6.0),
new CGlassBox(4.0,5.0,6.0)};
for(int i=0; i<4; i++){
pBoxes[i]->ShowVolume();
}
cout<Push(pBoxes[i]);
}
cout<<"现在开始读取Stack中的数据"<Pop()->ShowVolume();
}
//使用嵌套的Struct来定义堆栈中存储的对像,CStack类的确实现了一个堆栈
system("pause");
return 0;
}*/
//9.9 C++/CLI编程
//包括用户定义的类在内的所有C++/CLI类,默认情况下都是派生类,因此数值和引用类都是以System::Object这个标准作为基类的
//因为System::Object是所有C++/CLI类的基类,所以句柄类型system::Object^起到了与本地C++中可用来引用任何类型的对像的void*类型相同的作用
//9.9.1 装箱与拆箱
//供所有数值类型使用的System::Object基类还负责实现基本类型数值的装箱(boxing)和拆箱(unboxing)操作
//装箱是将它转换为垃圾回收堆上的一个对像,因此它会与基类数值一起承载完整的类型信息
//拆箱是装箱的逆向操作
//double value = 3.14159265;
//Object^ boxedValue = value;
//第二个语句强制装箱value,装箱后的表示由句柄boxedValue引用
//long^ number = gcnew(999999L);
//我们可以用解引用运算符对数值类型执行拆箱操作
//Console::WriteLine(*number);
/*#include "stdafx.h"
#include
using namespace std;
using namespace System;
int main(array ^args)
{
double value = 3.14159265;
Object^ boxedValue = value;
Console::WriteLine(boxedValue);
system("pause");
return 0;
}
*/
//9.9.2 C++/CLI类的继承
//String^ ToString();
//返回对像的String表示法,System::Object类中的实现返回字符串形式的类名,我们通常要在自己的类中重新该函数,以返回对像值的字符串表示
//bool Equals(Object^ obj)
//比较当前对像与obj,如果二者相等则返回true,否则返回false,这里的"相等"意味着引用相等性
//即两个对像是同一个,我们通常要在自己的类中重写该函数,以便宜当前对像与实参的值相等时,即二者的字符相等时返回true
//int GetHashCode()
//返回当前对像的散列码一个整数,在存储(key, object)对的集合中,散列码用于存储对象的键码,随后
//我们通过提供某个对像被存储时使用的键码,就可以从这样的集合中将该对像检索出来
/*#include "stdafx.h"
#include
using namespace std;
using namespace System;
//abstrcat定义抽像类
ref class Container abstract
{
public:
virtual double Volume() abstract;
//类名后面的abstract关键字,如果某个C++/CLI类包含等价于本地C++类中纯虚函数的函数
//那么我们必须将该类指定为abstract
virtual void ShowVolume()
{
Console::WriteLine(L"Volume is {0}", Volume());
}
};
ref class Box: Container
{
public:
virtual void ShowVolume() override
{
Console::WriteLine(L"Box usable volume is {0}", Volume());
}
virtual double Volume() override
{
return m_Length * m_Width * m_Height;
}
//Box类重写了从基类继承的Volume()函数,当需要重写基类中的某个函数,我们必须总是指定override关键字
//如果Box类不实现Volume()函数,那么它将是一个抽像类,而为了成功编译这个类,则需要将其指定为abstruct
Box():m_Length(1.0), m_Width(1.0), m_Height(1.0){}
Box(double lv, double wv, double hv):m_Length(lv), m_Width(wv), m_Height(hv){}
private:
protected:
double m_Length;
double m_Width;
double m_Height;
};
//引用类的基类总是公有的,默认情况下编译器认为是有public关键字的
//不能像本地C++版本中那样给形参提供默认值
ref class GlassBox: Box
{
public:
virtual double Volume() override
{
return 0.85 * m_Length * m_Width * m_Height;
}
GlassBox(double lv, double wv, double hv):Box(lv, wv, hv){}
};
ref class Stack
{
private:
ref struct Item
{
Object^ Obj;
Item^ Next;
Item(Object^ obj, Item^ next):Obj(obj), Next(next){}
};
Item^ Top;
public:
void Push(Object^ obj)
{
Top = gcnew Item(obj, Top);
}
Object^ Pop()
{
if(Top == nullptr){
return nullptr;
}
Object^ obj = Top->Obj;
Top = Top->Next;
return obj;
}
//需要注意的第一点是区别是函娄的形参和字段现在的都是句柄,因为我们是在处理引用类对像
//内部的结构Item现在存储着Object^类型的句柄,这样的句柄允许在堆栈中存储任何CLR类类型的对像
//这意味着无论是数值类还是引用类都能被压入堆栈
//这一点对本地C++中CStack类的重大改进,我们不必担心用Pop()函数时删除Item对像的问题
};
//总结这些类同本地C++类的区别
//1 只有引用类可以是派生类
//2 派生引用类的基类始终都是public
//3 引用类中没有定义的函数是抽像函数,必须使用关键字abstract声明
//4 我们必须通过在类名后面放上abstract关键字,将包含一个或多个抽像类显式指定为抽像类
//5 不包含抽像函数类也可以被指定为abstract,这种情况下我们将不能定义该类的实例
//6 当指定某个重定基类函数的函数时,我们必须显式使用override关键字
int main(array ^args)
{
array^ boxes = {gcnew Box(2.0, 3.0, 4.0),
gcnew GlassBox(2.0,3.0,4.0),
gcnew Box(5.0,6.0,7.0),
gcnew GlassBox(5.0,6.0,7.0)};
Console::WriteLine(L"开始显示boxes的值:");
for each(Box^ box in boxes){
box->ShowVolume();
}
Console::WriteLine(L"现在开始入栈操作:");
Stack^ stack = gcnew Stack;
for(int i=0; i<4; i++){
stack->Push(boxes[i]);
}
cout<<"现在开始出栈操作:";
System::Object^ item;
while((item = stack->Pop()) != nullptr){
safe_cast(item)->ShowVolume();
}
//重新定义stack值
for(int i=2; i<=12; i+=2)
{
Console::Write(L"{0,5}", i);
stack->Push(i);
}
Console::WriteLine();
while((item=stack->Pop()) != nullptr){
Console::Write(L"{0,5}", item);
}
Console::WriteLine();
system("pause");
return 0;
}
*/
//9.9.3 接口类
//接口类的定久看起来非常类似于引用类的定义,但是它是个完全不同的概念,接口类指定一级将由其它类实现的函数
//以提供标准化的,可提供某种体功能的方,数值类和引用类都可以实现接口,接口不定义任何自有的函数成员
//其指定的函数是由实现该接口的各个类来定义的
//我们可以像下面这样使上一个示例中的Box类实现System::IComparable接口
/*ref class Box : Container, IComparable
{
//接口名是在类类名Container后面,如果没有基类,则这里单独出现接口名
//引用类只有一个基类,但可以实现任意多的接口
//这样的类必须定义宣称要实现的各个接口指定的每一个函数
//
public:
virtual int COmpareTo(Object^ obj)
{
if(Volume() < safe_cast(obj)->Volume());
return -1;
else if(Volume() > safe_cast(obj)->Volume());
return 1;
else
return 0;
}
}*/
//9.9.4 定义接口类
//我们使用关键字interface class 或者interface struct定义接口类,无论是使用interface clas还是interface struct来定义接口
//接口的所有成员默认都是公有的,我们不能将它们指定为其它类型,接口的成员可以是函数,包括运算符函数,属性,静态字段和事件
//interface class IController: ITelevison, IRecorder
//{
//Members of IController
//}
//该接口继承了ITelevison IRecorder两个接口
//Box类必须实现IContainer接口类的两个函数成员,不然它就是一个抽像类,需要用abstract关键字来定义
//Box类中这两个孙函数那么 的定义没有附加override关键字,因为我们不是重定现有的函数,而是初次实现Volume()和ShowVolume()函数
#include "stdafx.h"
#include
using namespace std;
using namespace System;
interface class IContainer
{
double Volume();
void ShowVolume();
//两个函数实际上是抽像函数,因为接口永远不包括函数的定义,当然,我们可以给这两个函数添加abstruct关键字
//但这样做是不必要的,接口定义中的实例数可以指定为virtual和abstract但这也不是必需的
};
//C++/CLI中的接口名以I打头,这个约定
ref class Box: IContainer
{
public:
virtual void ShowVolume()
{
Console::WriteLine(L"CBox usable volume is {0}", Volume());
}
virtual double Volume()
{
return m_Length * m_Width * m_Height;
}
Box() : m_Length(1.0), m_Width(1.0), m_Height(1.0){}
Box(double lv, double wv, double hv):m_Length(hv), m_Width(wv), m_Height(hv)
{
}
protected:
double m_Length;
double m_Width;
double m_Height;
};
//引用类的基类总是公有的,默认情况下编译器认为是有public关键字的
//不能像本地C++版本中那样给形参提供默认值
ref class GlassBox: Box
{
public:
virtual double Volume() override
{
return 0.85 * m_Length * m_Width * m_Height;
}
GlassBox(double lv, double wv, double hv):Box(lv, wv, hv){}
};
ref class Stack
{
private:
ref struct Item
{
Object^ Obj;
Item^ Next;
Item(Object^ obj, Item^ next):Obj(obj), Next(next){}
};
Item^ Top;
public:
void Push(Object^ obj)
{
Top = gcnew Item(obj, Top);
}
Object^ Pop()
{
if(Top == nullptr){
return nullptr;
}
Object^ obj = Top->Obj;
Top = Top->Next;
return obj;
}
};
int main(array ^args)
{
array^ containers = {gcnew Box(2.0, 3.0, 4.0),
gcnew GlassBox(2.0,3.0,4.0),
gcnew Box(5.0,6.0,7.0),
gcnew GlassBox(5.0,6.0,7.0)};
Console::WriteLine(L"开始显示boxes的值:");
for each(IContainer^ container in containers){
container->ShowVolume();
}
Console::WriteLine(L"现在开始入栈操作:");
Stack^ stack = gcnew Stack;
for each(IContainer^ container in containers){
stack->Push(container);
}
cout<<"现在开始出栈操作:";
System::Object^ item;
while((item = stack->Pop()) != nullptr){
safe_cast(item)->ShowVolume();
}
system("pause");
return 0;
}