Visual C++ 2008入门经典 第九章类的继承和虚函数(三)
/////////////////////////////////////////////////////// //9.9.5 类和程序集 //C++/CLI应用程序总是驻留在一个或多个程序集中,因此C++/CLI类也要驻留在某个程序集中 //C++/CLI为类添加了确定某个类能否从驻留的程序集外部访问的可见性说明符,类驻留的程序集被称为该类的父程序集 //除了本地C++所有的public prvate和protected成员访问说明符以外. C++/CLI还为类成员添加了几个确定在不同程序集中可以从什么集团访问类成员的访问说明符 //1 类和接口的可见性说明符 //我们可以将非嵌套类,接口或枚举的可见性指定为private或public,public类在驻留的程序外部是可见和可访问的,而private类只能从父程序 //集中访问,类接口和枚举类型默认都是私有的,因此仅在其父程序集中才可见,如果要将某个类指定为public,我们呆需要 //像下面这样使用public关键字即可 //public interface class IContainer //默认为private //{ //Details of the interface //}; //2 类和接口成员的访问说明符 //C++/CLI添加了三个类成员访问说明符,internal, public protected和private protected /*public ref class MyClass { public: internal: public protected: //限制性少的关键字应用于程序集内部,限制性多的关键字应用于程序集外部,这种关键字对的顺序可以颠倒, //因此protected private 与private protected意义相同 private protected: }*/ //加载类库这块没有成功 //错误提示为 //1>f:\myprojects\visual.c++.2008入门经典\第九章类的继承和虚函数\ex9\GlassBox.h(3): fatal error C1107: 未能找到程序集“Ex9_16.dll”: 请使用 /AI 或通过设置 LIBPATH 环境变量指定程序集 //9.9.6 被指定为new的函数 //我们还可以在派生类中将某个函数指定义new,这样可以隐藏基类中签名相同的函数,而且新函数将不参与多态的行为 /* ref class NewBox : Box { public: virtual double Volume() new { return 0.5 * m_Lenght * m_Width * m_Height; } NewBox(double lv, double wv, double hv):Box(lv, wv, hv) { }; }; NewBox^ newBox = gcnew NewBox(2.0, 3.0, 4.0); Console::WriteLine(newBox->Volume()); //12 //因为新的Volume()函数隐藏了NewBox类从Box继承多态版本 //新的Volume()函数不是多态函数,因此使用指向基类类型的句柄进行动态调用时,新版本不会被调用 Box^ newBox = gcnew NewBox(2.0, 3.0, 4.0); Console::WriteLine(newBox->Volume());//24 //NewBox类中仅有的多态Volume()函数是从Box类继承的,因此本例中将调用继承的Volume()函数 */ //9.9.7 委托和事件 //事件是类的成员,这种成员使对像能够了在特定事件发生时发出信号,而为某个事件发出信号的过程涉及委托。 //委托的思想非常简单:委托是能够封装一个或多个指针的对像,这些指针指向具有特定形参列表和返回类型的函数 //1 声明委托 //委托的声明看起来就像是前面添加delegate关键字的函数原型,但事实上定义了两件事情: //委托对像的引用类型名以及可能与该委托有关的函数的形参列表和返回类型 //委托的引用类型以System::Delegate作为基类,因此委托类型总是要继承该基类的成员,虽然委托的声明看来像是在前面添加了delegate关键字的函数原型,但实际上既定义了该委托的引用类型,又定义了可能与该委托有关的函数的签名 //public delegate void Handler(int val); //该语句将委托的引用类型定义为Handler,这里的Handler类型是从System::Delegate派生的, //类型为Handler的对像可以包含拥有一个int类型的形参,返回类型为void的一个或多个函数的指针 //2 创建委托 //定义了委托类型之后,我们就可以创建该类型的委托对像,委托的构造函数有两种选择,一种是接受单个实参,别一种是接受两个实参 //接受单个实参的委托构造函数的实参, //必须是具有委托声明中指定的返回类型和形参列表的静态类函数成员或全局函数, //假设我们像下面这样定义了一个名为HandlerClass的类 /*public ref class HandlerClass { public: static void Fun1(int m) { Console::WriteLine(L"Function1 called with value {0}", m); } static void Func2(int m) { Console::WriteLine(L"Function2 colled with value {0}", m); } void Fun3(int m) { Console::WriteLine(L"Function3 colled with value {0}", m); } void Fun4(int m) { Console::WriteLine(L"Function4 colled with value {0}", m); } HandlerClass():value(1){} HandlerClass(int m):value(m){} protected: int value; }; //我们可以像下面这样创建一个Hadnler委托 Handler^ handler = gcnew Handler(HandlerClass::Fun1); //对像handler包含HandlerClass类中静态函数Func1的地址,如果我们调用这个委托,则HandlerClass::Fun1()函数将被调用,其实参与我们在委托调用中传递的实参相同,我们可以像下面这样编写委托调用 handler->Invoke(90); //直接调用委托 handler(90); //修稺handler委托的调用列表 handler += gcnew Handler(HandlerClass::Fun2); handler(80); //删除委托列表中的某一项 handler -= gcnew Handler(HandlerClass::Fun1); //委托的调用列表必须到少包含一个函数指针,如果我们使用减法运算删除所有函数指针,则结果将是nullptr //当我们使用有两个形参的委托构造函数时,第一个实参是CLR堆上某个对像的引用,第二个实参是该对像所属的类型中某个实例函数的地址, //因此,该构造函数创建的委托将包含一个由第二个实参指定的实例函数指针,以便宜供第一个实参指定的对像使用,下面是创建这种委托的方法 HandlerClass^ obj = gcnew HandlerClass; Handler^ handler2 = gcnew Handler(obj, &HandlerClass::Fun3); //第一条语句创建一个对像, //第二条语句为HandlerClass对像创建一个指向Fun3的函数委托,该委托要求提供int类型的实参,因此我们可以有下面这条语句来用它 handler2(70); //因为两个委托对像的类型相同,所以我们可以合并handler的调用列表与handler2委托的调用列表 Handler^ handler = gcnew Handler(HandlerClass::Fun1); handler += gcnew Handler(HandlerClass::Fun2); HandlerClass^ obj = gcnew HandlerClass; Handler^ handler2 = gcnew Handler(obj, &HandlerClass::Fun3); handler += handler2;*/ /* #include "stdafx.h" #include <iostream> using namespace std; using namespace System; public ref class HandlerClass { public: static void Fun1(int m) { Console::WriteLine(L"Function1 called with value {0}", m); } static void Fun2(int m) { Console::WriteLine(L"Function2 colled with value {0}", m); } static void MyFun(double x, String^ description) { Console::WriteLine(L"MyFun colled with x:{0} description:{1}", x, description); } void Fun3(int m) { Console::WriteLine(L"Function3 colled with value {0}", m); } void Fun4(int m) { Console::WriteLine(L"Function4 colled with value {0}", m); } HandlerClass():value(1){} HandlerClass(int m):value(m){} protected: int value; }; public delegate void Handler(int value); //该语句将委托的引用类型定义为Handler,这里的Handler类型是从System::Delegate派生的, public delegate void MyHandler(double x, String^ description); int main(array<System::String ^> ^args) { //Handler是上面定久的public delegage void Handler(int value)的定义 Handler^ handler = gcnew Handler(HandlerClass::Fun1); //直接在Handler上面定义一个委托fun1 Console::WriteLine(L"pointer to a static function:"); handler->Invoke(90); //合用Invoke()函数调用委托,然后只使用后跟实参列表的委托句柄进行调用 handler += gcnew Handler(HandlerClass::Fun2); Console::WriteLine(L"添加一个委托对像以后:"); handler->Invoke(80); HandlerClass^ obj = gcnew HandlerClass; Handler^ handler2 = gcnew Handler(obj, &HandlerClass::Fun3); handler += handler2; Console::WriteLine(L"合并两个handler委托以后:"); handler(70); Console::WriteLine(L"减去一个委托对像以后:"); handler -= gcnew Handler(HandlerClass::Fun1); handler(60); MyHandler^ myhandler = gcnew MyHandler(HandlerClass::MyFun); myhandler(111.11, "pli"); system("pause"); return 0; } */ //3 无约束的委托 //我们迄令所看到的委托都是有约束委托的示例,称之为有约束委托的原因是它们的调用列表中都有一组定的函数,我们还可以创建无约速的委托 //无约束的委托指向特定对像类型的形参列表和返回类型与委托声明一到处的实例函数 //因此,相同的委托可以调用指定类型的任何对像的实例函数, /*public delegate void UBHandler(ThisClass^, int value); //第一个参数指定this指针类型, //UBHandler类型的委托可以为该指针调用某个实例函数,该函数必须有int类型的单个形参,其返回类型必须是void, //因此,UBHandler类型的委托只能为ThisClass类型的对像调用函数,但该类型的对像可以是任意一个 UBHandler^ ubh = gcnew UBHandler(%ThisClass::Sum); public ref class ThisClass { public: void Sum(int n, String^ str) { Console::WriteLine(L"Sum result={0}", value+n); } void Product(int n, String^ str) { Console::WriteLine(L"Product result = {0}", value*n); } ThisClass(double v):value(v){}; private: double value; }; //当我们调用某个无约束的委托时,第一个实参是调用列表内函数的当前对像,随后的实参是传递给被调用函数的实参 ThisClass^ obj = gcnew ThisClass(99.0); ubh (obj, 5); //第一个实参是指向某个ThisClass对像的句柄,该对像是我们通过给类的构造函数传递数值99.0而在CLR堆中创建的 //该ubh调用的第二个实参是5, 因此结果是以5作为实参,为obj引用的对像调用的sum函数 ubh += gcnew UBHandler(&ThisClass::Product); */ /* #include "stdafx.h" #include <iostream> using namespace std; using namespace System; public ref class ThisClass { public: void Sum(int n, String^ str) //void Sum(int n) { Console::WriteLine(L"Sum result={0} str={1}", value+n, str); } void Product(int n, String^ str) { Console::WriteLine(L"Product result = {0}", value*n); } ThisClass(double v):value(v){}; private: double value; }; //声明一个委托对像 public delegate void UBHandler(ThisClass^, int value, String^ str); int main(array<System::String ^> ^args) { array<ThisClass^>^ thisgs = { gcnew ThisClass(5.0), gcnew ThisClass(10.0), gcnew ThisClass(15.0), gcnew ThisClass(20.0), gcnew ThisClass(25.0) }; UBHandler^ ubh = gcnew UBHandler(&ThisClass::Sum); for each(ThisClass^ thing in thisgs){ ubh(thing, 2, "Baby"); } ubh += gcnew UBHandler(&ThisClass::Product); for each(ThisClass^ thing in thisgs) { ubh(thing, 2, "Baby2"); } system("pause"); return 0; }*/ //4 创建事件 //发出某个事件发生的信号需要使用委托,该委托应该包含该事件发生时被调用的函数指针,我们要在程序中处理的大多数事件都与按钮或菜单项这样的控件有关,这些事件源于用户与程序的交互作用,但我们也可以在自己的程序代码中定义和触发事件 //事件是使用event关键字和委托名定义的引用类成员 /* public delegate void DoorHandler(String^ str); public ref class Door { public: event DoorHandler^ Knock; //有一个名为Knock的事件成员,该事件对应于DoorHandler类型的委托 //Knock是Door类的实例成员,但我们可以使用startic关键字将某个事件指定为静态类成员,还可以将某个事件声明为virtual //当某个Knock事件被触发时,它可以调用具有DoorHandler委托指定的形参列表和返回类型的函数 void TriggerEvents() { Knock("Fred"); Knock("Jane"); } //Door类还有一个解发两次的Knock事件的公有函数TriggerEvent(),两次解发使用不同的实参 //这两个实参将传递给已注册的接收Knock事件通知的函数 }; //定一个能够处理Knock事件的类 public ref class AnswerDoor { public: void ImIn(String^ name) { Console::WriteLine(L"Come in {0}, it's open.", name); } void ImOut(String^ name) { Console::WriteLine(L"Go away{0}, I'm out.", name); } }; //AnswerDoor类有两个能够了处理Knock事件的公有函数成员,因为二者的形参列表和返回类型与DoorHandler委托的声明所指定的一致 Door^ door gcnew Door; AnswerDoor^ answer = gcnew AnswerDoor; door->Knock += gcnew DoorHandler(answer, &AnswerDoor::ImIn); //第一条语句创建一个AnswerDoor类型的对像,我们需要该对像 //因为ImIn()和ImOut()函数不是静态类成员,然后,我们将DoorHandler委托类型的一个实例与door的Knock成员相同 //这完全就是给委托添加函数指针的过程,我们可以相同的方式,添加更多的录Knock事件被告触发时将调用事件处理函数 */ /* #include "stdafx.h" #include <iostream> using namespace std; using namespace System; public delegate void DoorHandler(String^ str); public ref class Door { public: event DoorHandler^ Knock; //有一个名为Knock的事件成员,该事件对应于DoorHandler类型的委托 //Knock是Door类的实例成员,但我们可以使用startic关键字将某个事件指定为静态类成员,还可以将某个事件声明为virtual //当某个Knock事件被触发时,它可以调用具有DoorHandler委托指定的形参列表和返回类型的函数 void TriggerEvents() { Knock("Fred"); Knock("Jane"); } //Door类还有一个解发两次的Knock事件的公有函数TriggerEvent(),两次解发使用不同的实参 //这两个实参将传递给已注册的接收Knock事件通知的函数 }; //定一个能够处理Knock事件的类 public ref class AnswerDoor { public: void ImIn(String^ name) { Console::WriteLine(L"Come in {0}, it's open.", name); } void ImOut(String^ name) { Console::WriteLine(L"Go away{0}, I'm out.", name); } }; int main(array<System::String ^> ^args) { Door^ door = gcnew Door; AnswerDoor^ answer = gcnew AnswerDoor; door->Knock += gcnew DoorHandler(answer, &AnswerDoor::ImIn); door->TriggerEvents(); door->Knock -= gcnew DoorHandler(answer, &AnswerDoor::ImIn); //注册answer对像的ImIn()成员,使之接收door对像中Knock事件的通知 door->Knock += gcnew DoorHandler(answer, &AnswerDoor::ImOut); door->TriggerEvents(); system("pause"); return 0; } */ //9.9.8 引用类的析构函数和终结器 //我们可以用为本地C++类定义析构函数时所用的相同方式,为引用类定义析构函数,当某个引用类的句柄离开其作用域时,或者当访类的对像是另一个正在被销毁的对像组成部分时,类的析构函数将被调用 /*public ref class MyClass { !MyClass() { cout<<"code to clean-up when an object is......"<<endl; } };*/ //在类中定义终结器的方法与定义析构函数的类似,但需要用!代替为析构函数使用的类名前面的~符号 //与析构函数一样,我们决不能为终结器提供返回类型,而终结器的访问说明符也被忽略 /*#include "stdafx.h" #include <iostream> using namespace std; using namespace System; ref class MyClass { public: MyClass(int n) : value(n){} ~MyClass() { Console::WriteLine("MyClass object({0}) destructo called.", value); } !MyClass() { Console::WriteLine("MyClass object({0}) finalizer called.", value); } private: int value; }; int main(array<System::String ^> ^args) { MyClass^ obj1 = gcnew MyClass(1); MyClass^ obj2 = gcnew MyClass(2); MyClass^ obj3 = gcnew MyClass(3); delete obj1; obj2->~MyClass(); Console::WriteLine(L"执行完成!"); system("pause"); return 0; }*/ //如果某个类既有终结器,又有析构函数,则销毁对像时只能调用其中之一, //如果我们以编程的方式销毁对像,则析构函数被调用 //如果对像因离开作用域而自然消失,则终结器被调用,由此还要台得出下面的结论 //如果我们依赖终结器来完成销毁对像之后的清理工作,则不应该显示式删除对像 //如果无论对像以怎样的方式终止,都希望确保对像使用的不受管理的资源能够得到清理,则应该在类中实现析构函数,又实现终结器 //9.9.9 通用类 //C++/CLI给我们提供了定义通用类的功能,具体类将在运行时通过实例化通过类产生 //我们可以定义通用数值类,通用引用类,通用接口类的通用委托 /*genreic<typename T> ref class Stack { private: ref struct Item { T Obj; Item^ Next; Item(T obj, Item^ next):Obj(obj), Next(next){} }; Item^ Top; public: void Push(T obj) { Top = gcnew Item(obj, Top); } T Pop() { if(Top == nullptr){ return T(); //相当于 nullptr } //我们在返回类型为形参的情况下不能返回nullptr,因为类型实参可能是数值类型, //解决方法是返回T() 以调用类型T中无参数的构造函数,这样做的结果等价于为数值类型返回0 //为句柄类型返回nullptr T obj = Top->Obj; Top = Top->Next; return obj; } };*/ //T是通过定义由类型实参代替的,因此与原来版本相比通用类类型的主要优点是更加安全,但不会丧失任何灵活性, //我们可以将MyClass^类型 String^类型或任何句柄类型的对像混合压入相同的堆栈 //但通过类例的Push()函数只能接受实参类型的对,对像以实参为基类的类型的对像 /*#include "stdafx.h" #include <iostream> using namespace std; using namespace System; ref class Box { public: void ShowVolume() { Console::WriteLine(L"CBox usable volume is {0}", Volume()); } 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; }; ref class GlassBox: Box { public: double Volume() { return 0.85 * m_Length * m_Width * m_Height; } GlassBox(double lv, double wv, double hv):Box(lv, wv, hv){} }; generic<typename T> ref class Stack { private: ref struct Item { T Obj; Item^ Next; Item(T obj, Item^ next):Obj(obj), Next(next){} }; Item^ Top; public: void Push(T obj) { Top = gcnew Item(obj, Top); } T Pop() { if(Top == nullptr){ return T(); //相当于 nullptr } //我们在返回类型为形参的情况下不能返回nullptr,因为类型实参可能是数值类型, //解决方法是返回T() 以调用类型T中无参数的构造函数,这样做的结果等价于为数值类型返回0 //为句柄类型返回nullptr T obj = Top->Obj; Top = Top->Next; return obj; } }; int main(array<System::String ^> ^args) { array<Box^>^ boxes = { gcnew Box(2.0,3.0,4.0), gcnew GlassBox(2.0,3.0,4.0), gcnew Box(4.0,5.0,6.0), gcnew GlassBox(4.0,5.0,6.0) }; for each(Box^ box in boxes){ box->Volume(); } //创建一个容器 Stack<Box^>^ stack = gcnew Stack<Box^>; for each(Box^ box in boxes){ stack->Push(box); } Box^ item; while((item=stack->Pop()) != nullptr){ safe_cast<Box^>(item)->ShowVolume(); } Stack<int>^ numbers = gcnew Stack<int>; for(int i= 2; i<12; i+=2){ numbers->Push(i); } int number; while((number = numbers->Pop()) != 0){ Console::Write(L"{0,10}", number); } Console::WriteLine(); system("pause"); return 0; } //1 通用接口类 //我们可以定义通用接口,其方法与定义通用引用类的相同,通用引用类可以根据通用接口进行定义, generic<typename T> public interface class IStack { void Push(T obj); T Pop(); }; //实现IStack<>通用接口的能用Stack<>类的定义如下 //该通用类从IStack接口类中继承 generic<typename T> ref class Stack : IStack<T> { private: ref struct Item { T Obj; Item^ Next; Item(T obj, Item^ next):Obj(obj), Next(next){} }; Item^ Top; public: virtual void Push(T obj) { Top = gcnew Item(obj, Top); } virtual T Pop() { if(Top ==nullptr){ return T(); } T obj = Top->obj; Top = Top->Next; return obj; } //Push()和Pop()函数现在必须被指定为virtual,因为它们在IStack接口中是虚函数 } */ //通用集合类 //集合类是以特定方式组织和存储对像的类,链接和堆栈都是典型的集合类示例 //System::Conooections::Generic命名空间包含许多实现了强类型集合的通用集合类似 //List<t> 将类型为T的项存入某个简单的列表,该列表的大小可能是需要时自动增 //LinkedList<T> 将类型为T的项存入双链表 //Stack<T> 将类型为T的项存入堆栈,堆栈是一种先入后出的存储机制 //Queue<T> 将类型为T的项存入队列,队列是一种先入先出和存储机制 //Dictionary<K,V> 存储键、值对,其中键属于K类型,值属于V类型 //3 通用列表List<T> //List<T>定义了一个通用的列表,该列表的大小可以在需要时自动增长,我们可以使用Add()函数给列表添加项 //还可以使用索引访问List<T>中存储的项,就像是使用数组一样 //List<int> numbres = gcnew List<int> //for(int i=0; i<1000; i++){ //numbres->Add(2*i+1); //} //向列表中插入元素 //Insert() /* int sum = 0; for(int i=0; i<numbres->Count; i++){ sum += numbres[i]; } for each(int n in numbres) sum += n; */ /* //4 通用双链表示LinkedList<T> //LinkedList<T>函数定义了一个包含前向和后向指针的链表,因此我们可以在两个方向上迭代这种列表 //我们可以像下面这样定义一个存储浮点数的链表 //LinkedList<double>^ values = gcnew LinkedList<double> for(int i=0; i<1000; i++){ values->AddLast(2.5*i); //AddLast函数将某项添加到链表的最后,通用使用AddFirst()函数 //我们可以将新项添加到链表的开始,作为另一种选择,我们可以使用AddHead()和AddTail()函数做相同的事情 } //Find()函数将返回一个LinkedListNode<T>^ 类型的句柄,该句柄指向的链表节点包含我们给Find()传递的实参数值, //该句柄可用来在找到的节点之前或之后插入新值 LinkedListNode<double>^ node = values->Find(20.0); if(node != nullptr){ values->AddBefore(node, 19.9); } //我们可以使用AddAfter()函数在给定节点的后面插入新值,搜索链表的速度相对较慢,因为需要顺序地迭代所有元素 double sumd = 0; for each(double v in values) sumd += v; //Count属性返回链表中项的数量 //Head和Tail属性返回第一项和最后一项的数值 //First和Last属性分别与Head和Tail相同 */ // 5 存储键/值对的通用词典Dictionary<TKey, TValue> //通用的Dictionary<>集合类要求提供两个类型实参,第一个是键的类型, //第二个是与键相关的值的类型,当需要存储的是对像时,而其中一个对像又是访问另一个对像的键时,词典就特别有用了 //Dictionary<Name^, PhoneNumber^>^ phonebook = gcnew Dictionary<Name^, PhoneNumber^>; //两个类型实参是Name^ 和PhoneNumber^, 因此键是姓名的句柄,值是电话号码的句柄 //我们可以像下面这样在phonebook词典中添加新的记录项 //Name^ name = gcnew Name("Jim", "Jones"); /*PhoneNumber^ number = gcnew PhoneNumber(914,316,2233); phonebook->add(name, number); //检索词典中的记录项,可以使用默认的索引属性 try { PhoneNumber^ theNumber = phonebook[name]; }catch(KeyNotFoundException^ knfe) { Console::WriteLine(knfe); }*/ /* #include "stdafx.h" #include <iostream> using namespace std; using namespace System; using namespace System::Collections::Generic; ref class Name { public: Name(String^ name1, String^ name2):First(name1), Second(name2){} virtual String^ ToString() override{ return First+L" "+ Second;} private: String^ First; String^ Second; }; ref class PhoneNumber { public: PhoneNumber(int area, int local, int number):Area(area), Local(local), Number(number){} virtual String^ ToString() override { return Area+L" "+Local+L" "+Number; } private: int Area; int Local; int Number; }; int main(array<System::String ^> ^args) { Console::WriteLine(L"Creating a List<T> of integers:"); List<int>^ numbers = gcnew List<int>; for(int i=0; i<1000; i++){ numbers->Add(2*i+1); } int count=0; for(int i=0; i<1000; i++){ count += numbers[i]; } Console::WriteLine(L"计算List<int>的数值总和为:{0}", count); Console::WriteLine(L"开始定义一个LinkedList<double>:"); LinkedList<double>^ values = gcnew LinkedList<double>; for(int i = 0 ; i<1000 ; i++) values->AddLast(2.5*i); //AddTail不行,用AddLast才行,就是在前面插入不行,只能在后面插入 //LinkedList<double>^ values = gcnew LinkedList<double>; //for(int i = 0 ; i<1000 ; i++) //values->AddTail(2.5*i); //神也,这里执行不了,说 //for(int i=0; i<1000; i++){ // values->AddTail(2.5*i); //} //九章类的继承和虚函数.cpp(2377): error C2039: “AddTail”: 不是“System::Collections::Generic::LinkedList<T>”的成员 // with // [ // T=double // ] double sum = 0.0; for each(double d in values){ sum += d; } Console::WriteLine("总和为:{0}", sum); //查询值为20.0的node LinkedListNode<double>^ node = values->Find(20.0); values->AddBefore(node, 19.9); //指定值后面添加元素 AddBefor values->AddBefore(values->Find(30.0), 30.1); sum = 0.0; for each(double v in values){ sum += v; } Console::WriteLine("插入两个值后的总和为:{0}", sum); Console::WriteLine(L"开始创建Dictionary<K,V> of name/number:"); Dictionary<Name^, PhoneNumber^>^ phonebook = gcnew Dictionary<Name^, PhoneNumber^>; Name^ name =gcnew Name("Jim", "Jones"); PhoneNumber^ number = gcnew PhoneNumber(914, 316, 2233); phonebook->Add(name, number); phonebook->Add(gcnew Name("Fred", "Fong"), gcnew PhoneNumber(123,456,789)); phonebook->Add(gcnew Name("Janet", "Smith"), gcnew PhoneNumber(515,224, 6864)); Console::WriteLine(L"list的所有电话号:"); for each(PhoneNumber^ number in phonebook->Values){ Console::WriteLine(number); } Console::WriteLine(L"所有姓名和电话:"); for each(Name^ name in phonebook->Keys) { Console::WriteLine(L"{0} : {1}",name, phonebook[name]); } system("pause"); return 0; }*/ //总结: /*1 派生类继承基类中除构造函数,析构函数和重载函数运算符以外的所有成员 2 基类中声明为private成员在任何派生类中都不能访问,为了既获得private关键字的效果,又允许在派生类中访问,我们应该使用protected代替private 3 我们可以为某个派生类将基类指定为public private protected,如果什么也不指定,则默认的关键字为private 继承成员的访问级别可能改变,变化级别取决于基类指定的访问关键字 4 如果要编写派生类的构造函数,则不仅必须安排初始化派生类的数据成员,还必须正确安排初始化基类的数所成员 5 基类中的函数可以被声明为virtual,这样将允许在执行时根据调用该函数的当前对像的类型,选择派生类中出现该函数的其他定义 6 我们应该将包含虚函数的本地C++基类中的析构函数声明为virutal,以确保为动态创建的派生类对像选择正确的析构函数 7 本地C++类可以被指定为另一个类的friend,这种情况下,friend类的所有函数成员都可以访问另一个类的所有成员 //如果类A是B的friend,则类B并非是类A的friend,除非我们是这样声明的 8 通过在函数声明最后添加=0, 我们可以将本地C++基类中的虚函数指定为纯虚函数 这样,该类就成为了不能创建任何对像的抽像类,在任何派生类中,都必须定义所有纯虚函数 //如果不然,该派生类也将成不抽像类 9 C++/CLI引用类可以是另一个引用类的派生类,数值类不能是派生类 10 接口类声明一组可以由引用类实现的,表示具体功能公有函数,接口类可以包含公有的函数,事件和属生, 接口类还可以定义静态的接口成员,函数事件和属性event,它们将会被实现该接口的类继承 11 接口类可以是另一个接口类的派生类,派生的接口包含两个接口的成员 12 委托对像封装了一个或多个指针,指针指向返回类型和形参列表相同的函数,调用委托将调用委托指向的所有函数 13 类的事件成员在特定事件发生时,可以通过调用一个或多个已经注册的该事件的处理函数来发出信号 14 通用类是运行在实例化的带参数的类型,我们实例化通用类时为类型形参提供的实参, 可以是数值类类型,也可以是引用型类型 15 System::Collections::Generic命名空间包含通用的集合类,可用于定义任何C++/CLI类对像的,具备类型安全性的集合 16 我们可以在单独的程序集中创建C++/CLI类库,类库驻留在.dll文件中 */