C++/CLI——读书笔记《Visual C++/CLI从入门到精通》 第Ⅱ部分

=================================版权声明=================================

版权声明:本文为博主原创文章 未经许可不得转载 

请通过右侧公告中的“联系邮箱(wlsandwho@foxmail.com)”联系我

未经作者授权勿用于学术性引用。

未经作者授权勿用于商业出版、商业印刷、商业引用以及其他商业用途。                   

本文不定期修正完善,为保证内容正确,建议移步原文处阅读。                                                               <--------总有一天我要自己做一个模板干掉这只土豆

本文链接:http://www.cnblogs.com/wlsandwho/p/4713311.html

耻辱墙:http://www.cnblogs.com/wlsandwho/p/4206472.html

=======================================================================

 第九章 值类型

  值类型

    C++等价形式是.net类型名称的别名,用哪个都一样。

    所有值类型都是从System::ValueType继承。

    栈上存储

    不被垃圾回收

    直接访问没差别

    值类型有必要时可以当作对象使用

  结构

    结构是值类型而非引用类型。(例如表示坐标的点)

    .net结构的优点就是可以由其他语言来使用。

    不支持继承也不能作为基类

    能实现接口

    复制结构,是拷贝。

    结构成员不可以是引用类型,引用成员必须要垃圾回收。

    可嵌套定义。

    value struct Point

    {

      int x;

      int y;

    };

    value struct Person

    {

      String^ name;

      value struct Date { int yyyy,mm,dd;};

      Date dob;

    };

  枚举

    值类型 派生自System::Enum,System::ValueType。

    栈上

    枚举成员要有类型名称限定

    Format函数  String^ s=Enum::Format(WeekDay::typeid,w,"G");

    一定要有public或private,因为C++11标准产生C2644错误。

    枚举支持任何整数类型,节省内存

      public enum class Weekday:char

=======================================================================

第十章 操作符重载

  操作符重载

    C++/CLI的操作符重载限制比较大,主要是因为在.net中要兼容各语言。

      遵循CLS

      gcnew和delete不恩那个重载因为内存是由.net的运行时负责的。

    Equals函数

          virtual bool Equals(Object^ other) override
          {
              IntVal^ obj = dynamic_cast<IntVal^>(other);
              if (obj==nullptr)
              {
                  return false;
              }

              return value == obj->value;
          }

       重写Equals时也应该重写GetHashCode

    标准C++重写++时是前++和后++

    C++/CLI重写++时只有++

    转换操作符+精彩操作符

      static operator IntVal(int v)

      {

        return IntVal(v);

      }

      static IntVal operator+(IntVal liv,IntVal riv)

      {

        IntVal result(liv.value+riv.value);

        return result;

      }

 1 value struct IntVal
 2 {
 3 private:
 4     int value;
 5 public:
 6     IntVal(int v):value(v){}
 7     int getVal() { return value; }
 8     
 9 //     IntVal operator+(IntVal rhs)
10 //     {
11 //         IntVal result(value + rhs.value);
12 //         return    result;
13 //     }
14 
15 //     IntVal operator+(int rhs)
16 //     {
17 //         IntVal result(value + rhs);
18 //         return result;
19 //     }
20 
21 //     static IntVal operator+(int lhs, IntVal rhs)
22 //     {
23 //         IntVal result(lhs + rhs.value);
24 //         return result;
25 //     }
26 
27     static operator IntVal(int v)
28     {
29         return IntVal(v);
30     }
31 
32     static IntVal operator+(IntVal lhs, IntVal rhs)
33     {
34         IntVal result(lhs.value + rhs.value);
35 
36         return result;
37     }
38 
39     static bool operator==(IntVal lhs, IntVal rhs)
40     {
41         return lhs.value == rhs.value;
42     }
43 
44     static bool operator!=(IntVal lhs, IntVal rhs)
45     {
46         return !(lhs == rhs);
47     }
48 
49     virtual bool Equals(Object^ other) override
50     {
51         IntVal^ obj = dynamic_cast<IntVal^>(other);
52         if (obj==nullptr)
53         {
54             return false;
55         }
56 
57         return value == obj->value;
58     }
59 
60     static IntVal operator++(IntVal i)
61     {
62         i.value++;
63         return i;
64     }
65 };
 1 ref    struct LongVal
 2 {
 3 private:
 4     long value;
 5 public:
 6     LongVal(long v) :value(v) {}
 7     int getVal() { return value; }
 8     
 9     static operator LongVal^(long l)
10     {
11         return gcnew LongVal(l);
12     }
13 
14     static LongVal^ operator+(LongVal^ lhs, LongVal^ rhs)
15     {
16         LongVal^ result = gcnew LongVal(lhs->value + rhs->value);
17 
18         return result;
19     }
20 };
 1 int main(array<System::String ^> ^args)
 2 {
 3     //Console::WriteLine(L"Hello World");
 4     IntVal one(1);
 5     IntVal two(2);
 6     IntVal three;
 7 
 8     three = one + two;
 9     Console::WriteLine(three.getVal());
10 
11     IntVal four;
12     four = two + 2;
13     Console::WriteLine(four.getVal());
14 
15     IntVal five;
16     five = 3 + two;
17     Console::WriteLine(five.getVal());
18 
19     IntVal somenum(2);
20     if (somenum == 2)
21     {
22         Console::WriteLine(L"somenum == 2");
23     }
24 
25     if (somenum != 3)
26     {
27         Console::WriteLine(L"somenum != 3");
28     }
29 
30     IntVal six(6), seven(7);
31     if (!six.Equals(seven))
32     {
33         Console::WriteLine(L"six != seven");
34     }
35 
36     LongVal^ lone = gcnew LongVal(1);
37     LongVal^ ltwo = gcnew LongVal(2);
38     LongVal^ lthree = lone + ltwo;
39     Console::WriteLine(lthree->getVal());
40 
41     return 0;
42 }

 =======================================================================

第十一章 异常处理

  类型转换

    safe_cast 转换失败抛出异常

    dynamic_cast转换失败返回空指针

  捕捉System::Exception派生类的对象

  C++

    构造函数 重载操作符——>异常在这些地方很有用

  C++/CLI

    传统C++异常

    C++/CLI异常

    SEH

  抛出异常

    

  形式

    try

    {

      if(a<0)

        throw gcnew ArgumentException(L"Test by WLS");

    }

    catch(ArgumentException^ ex)

    {  

      Console::WriteLine(L"Exception caught in Test by WLS");

      throw;

    }

    catch(Exception^)//捕捉所有异常 但会丢失所有异常信息

    {

    }

  创建自己的异常类型

    ref class WLSException:System::Exception

    {

      public:

        int ErrorNum;//自定义错误号

        WLSException(String^ msg,int num):Exception(msg),ErrorNum(num){}

    };

    使用时 throw gcnew WLSException(e->Message,666);

=======================================================================

第十二章  数组和集合

  用size_t比int要好

  泛型类型

    generic <typename T>

    ref class MyList

    {

    public:

      void Add(T num);

    }

  枚举器

    IEnumerator接口

    只能读取  修改还是要用常规循环

    迭代器模式  遍历任何集合  不保证顺序

    初始位置第一个之前

    MoveNext方法  移动到下一个元素,没有就返回false

    Current属性  当前项

    Reset方法   重置到第一个之前

  托管数组

    所有的托管数组都继承自System::Array

    array<类型,维度> handle_name

    托管堆

    垃圾回收

    索引从0开始 越界访问抛出异常

    arr1->Length  数组各维度的长度和

    arr1->GetLength(2)  第2维的长度

 1 array<Person^>^ arr3;//支持各种类型
 2 
 3 array<int>^ arr1 = { 1,2,3 };//C++风格
 4 
 5 array<int>^ arr2= gcnew array<int>(3) {4,5,6};
 6 
 7 array<int>^ arr3 = gcnew array<int>() {7,8,9};//为什么这个我的VS2015社区版不通过?  error C2748: 创建 托管 数组时必须提供数组大小或数组初始值设定项
 8 
 9 array<int, 2>^ arr1= gcnew array<int, 2>(3,3);//二维数组
10 Console::WriteLine(arr1->Length);
11 Console::WriteLine(arr1->GetLength(0));
12 Console::WriteLine(arr1->GetLength(1));
13 for (int i = 0;i < arr1->GetLength(0);i++)
14 {
15     for (int j = 0;j<arr1->GetLength(1);j++)
16     {
17         arr1[i,j] = i*j;//访问方式好独特,一个“[]”里用“,”分隔各个维度
18     }
19 }
20 
21 for (int i = 0;i < arr1->GetLength(0);i++)
22 {
23     for (int j = 0;j < arr1->GetLength(1);j++)
24     {
25         Console::WriteLine(arr1[i, j]);
26     }
27 }
1 array<String^>^ arr = gcnew array<String^>(SIZE) {gcnew String(L"abc"), gcnew String(L"def")};//初始化
2 
3 array<String^>^ arrs = gcnew array<String^>(SIZE);
4 arrs[0] = gcnew String(L"abc");
5 arrs[1] = L"def";
 1 //多维数组
 2 array<int, 2>^ arr1 = { {1,2,3},{4,5,6} };
 3 for (int i = 0;i < arr1->GetLength(0);i++)
 4 {
 5     for (int j = 0;j < arr1->GetLength(1);j++)
 6     {
 7         Console::WriteLine(arr1[i, j]);
 8     }
 9 }
10 
11 array<int, 2>^ arr2 = gcnew array<int, 2>{ {7, 8, 9}, { 10,11,12 }};
12 for (int i = 0;i < arr2->GetLength(0);i++)
13 {
14     for (int j = 0;j < arr2->GetLength(1);j++)
15     {
16         Console::WriteLine(arr2[i, j]);
17     }
18 }

 怎么在多维数组中使用foreach来遍历其中的某一维呢?

例如遍历array<String^, 2>^ arr3 = gcnew array<String^, 2>{ {L"aa", L"bb", L"cc"}, { L"ee",L"ff",L"gg" }};的第二维的元素?

=======================================================================

第十三章  属性

  C++/CLI支持两种属性

    标量属性  通过取值赋值访问单个值  属性不一定是数据成员可以是导出值

    索引属性  使用[]来访问属性

  关键字 property

    构造函数里应该优先使用属性进行初始化而不是直接使用数据成员

    可以在属性里使用throw抛出异常

  自动实现属性

    property String^ Name;//默认实现get和set

  只读或只写属性

    property String^ Name

    {

      //只实现get或者set

      String^ g/set(){...}

    }

  继承、接口

    属性可以是virtual也可以是纯virtual的,可以在继承和接口中使用

 1 ref class CShape abstract
 2 {
 3 public:
 4     virtual property double    Area;
 5 };
 6 
 7 ref class CCricle:CShape
 8 {
 9 public:
10 
11     CCricle(double r) { m_nRadius = r; }
12 
13     virtual property double Area
14     {
15         double get() override
16         {
17             return Math::PI*m_nRadius*m_nRadius;
18         }
19     }
20 
21     void PrintArea()
22     {
23         Console::WriteLine(L"The Area is {0}",Area);
24     }
25 
26 private:
27     double m_nRadius;
28 };
29 
30 
31 
32 int main(array<System::String ^> ^args)
33 {
34     CCricle^ oCricle = gcnew CCricle(4.0);
35     oCricle->PrintArea();
36 
37     return 0;
38 }

  索引属性

    默认属性

      类可以有多个索引器(索引属性),必须根据名称显示的使用。(下面的oBank->Balance[234567]

      名为default的索引属性可以在类对象上直接使用。(下面的CAccount^ pA = oBank[234567]

  1 #include "stdafx.h"
  2 
  3 using namespace System;
  4 using namespace System::Collections::Generic;
  5 
  6 //////////////////////////////////////////////////////////////////////////
  7 ref class CAccount
  8 {
  9 public:
 10     CAccount(long lAccNum,double dBalance,double dLimit);
 11     ~CAccount();
 12 
 13     property long AccountNumber
 14     {
 15         long get() { return m_lAccNumber; }
 16     }
 17 
 18     property double Balance
 19     {
 20         double get() { return m_dBalance; }
 21     }
 22 
 23     property double OverdraftLimit
 24     {
 25         double get() { return m_dLimit; }
 26         void set(double dValue)
 27         {
 28             if (dValue<0)
 29             {
 30                 throw gcnew ArgumentException(L"Limit can not be negative");
 31             }
 32 
 33             m_dLimit = dValue;
 34         }
 35     }
 36 
 37 private:
 38     long m_lAccNumber;
 39     double m_dBalance;
 40     double m_dLimit;
 41 };
 42 
 43 CAccount::CAccount(long lAccNum, double dBalance, double dLimit)
 44 {
 45     Console::WriteLine(L"Account:Constructor");
 46 
 47     if (lAccNum<0 || dLimit<0)
 48     {
 49         throw gcnew ArgumentException(L"Bad Arguments to constructor");
 50     }
 51 
 52     m_lAccNumber = lAccNum;
 53     m_dBalance = dBalance;
 54     m_dLimit = dLimit;
 55 }
 56 
 57 CAccount::~CAccount()
 58 {
 59 }
 60 //////////////////////////////////////////////////////////////////////////
 61 ref class CBank
 62 {
 63 public:
 64     CBank();
 65     ~CBank();
 66 
 67     bool AddAccount(CAccount^ oAccount)
 68     {
 69         if (m_listAccounts->Contains(oAccount))
 70         {
 71             return false;
 72         }
 73         else
 74         {
 75             m_listAccounts->Add(oAccount);
 76         }
 77 
 78         return true;
 79     }
 80 
 81     bool RemoveAccount(CAccount^ oAccount)
 82     {
 83         if (m_listAccounts->Contains(oAccount))
 84         {
 85             m_listAccounts->Remove(oAccount);
 86 
 87             return true;
 88         }
 89         
 90         return false;
 91     }
 92 
 93     property double Balance[long]
 94     {
 95         double get(long lIndex)
 96         {
 97             for each (CAccount^ var in m_listAccounts)
 98             {
 99                 if (var->AccountNumber==lIndex)
100                 {
101                     return var->Balance;
102                 }
103             }
104 
105             throw gcnew ArgumentOutOfRangeException(L"No Such Account");
106         }
107     }
108 
109     property CAccount^ default[long]
110     {
111         CAccount^ get(long lIndex)
112         {
113             for each (CAccount^ var in m_listAccounts)
114             {
115                 if (var->AccountNumber == lIndex)
116                 {
117                     return var;
118                 }
119             }
120 
121             throw gcnew ArgumentOutOfRangeException(L"No Such Account");
122         }
123     }
124 private:
125     List<CAccount^>^ m_listAccounts;
126 };
127 
128 CBank::CBank()
129 {
130     Console::WriteLine(L"Bank:Constructor");
131 
132     m_listAccounts = gcnew List<CAccount^>();
133 }
134 
135 CBank::~CBank()
136 {
137 }
138 
139 
140 int main(array<System::String ^> ^args)
141 {
142     CBank^ oBank = gcnew CBank();
143 
144     CAccount^ oAccount1 = gcnew CAccount(123456, 10.0, 0.0);
145     CAccount^ oAccount2 = gcnew CAccount(234567, 110.0, 10.0);
146     CAccount^ oAccount3 = gcnew CAccount(345678, 1110.0, 110.0);
147 
148     oBank->AddAccount(oAccount1);
149     oBank->AddAccount(oAccount2);
150     oBank->AddAccount(oAccount3);
151 
152     CAccount^ pA = oBank[234567];
153     Console::WriteLine(L"The Account Number {0} has the banlance {1}.", pA->AccountNumber,oBank->Balance[234567]);
154 
155     return 0;
156 }

(为什么我感觉我的代码写的有点问题,虽然可以跑?Balance属性真的这么写吗?)

=======================================================================

第十四章  委托和事件

   委托是特殊的类

    原理是将函数的执行委托给一个中间对象,调用具有特定签名的一个或者多个函数。

    C++/CLI的所有委托都是System::MulticastDelegate。

    关键字 delegate

      delegate double SomeOperating(double);

      只能调用托管类的成员函数(静态非静态都可以)。

        静态成员函数只需要传递函数地址

        非静态成员函数需要传递对象和函数地址

      委托创建好后不能改变调用的函数,但是可以重新gcnew一个新的,垃圾自动回收。

      调用委托可以使用invoke也可以使用委托的仿函数。

      MulticastDelegate使用Combine和Remove来操作调用列表。

      MulticastDelegate使用合并其他委托的方法来生成。

      MulticastDelegate的调用顺序由合并顺序决定。

      MulticastDelegate通常用不返回值的函数,但也可以返回值,一般是最后一个的结果。想要获得某个结果可以遍历委托列表。

 1 #include "stdafx.h"
 2 
 3 using namespace System;
 4 
 5 delegate double NumbericOp1(double);
 6 delegate double NumbericOp2(double, double);
 7 
 8 ref class Ops
 9 {
10 public:
11     static double Square(double dNum) { return dNum*dNum; }
12     static double Cube(double dNum) { return dNum*dNum*dNum; }
13     
14     double MultiAandB(double dNum1, double dNum2) { return dNum1*dNum2; }
15 };
16 
17 int main(array<System::String ^> ^args)
18 {
19     NumbericOp1^ NOp1 = gcnew NumbericOp1(Ops::Square);//静态函数//编译通过了
20 
21     double dTempNum1 = 10.0;
22 
23     Console::WriteLine(L"Square({0}) = {1}",dTempNum1,NOp1->Invoke(dTempNum1));
24     Console::WriteLine(L"Square({0}) = {1}", dTempNum1, NOp1(dTempNum1));
25 
26     NOp1 = gcnew NumbericOp1(Ops::Cube);//静态函数//编译通过了
27 
28     Console::WriteLine(L"Square({0}) = {1}", dTempNum1, NOp1->Invoke(dTempNum1));
29     Console::WriteLine(L"Square({0}) = {1}", dTempNum1, NOp1(dTempNum1));
30 
31     //////////////////////////////////////////////////////////////////////////
32     double dTempNum2 = 2.0;
33     double dTempNum3 = 3.0;
34 
35     Ops^ objOps=gcnew Ops();
36 
37     NumbericOp2^ NOp2;
38     NOp2 = gcnew NumbericOp2(objOps, &Ops::MultiAandB);//非静态函数
39 
40     Console::WriteLine(L"multi({0},{1})={2}", dTempNum2,dTempNum3,NOp2->Invoke(dTempNum2,dTempNum3));
41     Console::WriteLine(L"multi({0},{1})={2}", dTempNum2, dTempNum3, NOp2(dTempNum2, dTempNum3));
42 
43     return 0;
44 }
 1 #include "stdafx.h"
 2 
 3 using namespace System;
 4 
 5 delegate void PrintSomething(int);
 6 
 7 delegate int DOperation(int);
 8 
 9 ref class CClient1
10 {
11 public:
12     static void Print(int nNum) { Console::WriteLine(L"CClient1 {0}",nNum); }
13     int DoubleNum(int nNum) { return nNum<<1; }
14 };
15 
16 ref class CClient2
17 {
18 public:
19     static void Print(int nNum) { Console::WriteLine(L"CClient2 {0}",nNum); }
20     int DDoubleNum(int nNum) { return nNum << 2; }
21 };
22 
23 
24 int main(array<System::String ^> ^args)
25 {
26     PrintSomething^ PS1=gcnew PrintSomething(CClient1::Print);
27     PrintSomething^ PS2=gcnew PrintSomething(CClient2::Print);
28     PrintSomething^ PS3;
29     PS3+= PS1+PS2;
30     PS3(2333);
31 
32     Console::WriteLine(L"-------------");
33     PS3 += PS3+PS3;
34     PS3(233);
35 
36     Console::WriteLine(L"-------------");
37     PrintSomething^ PS4;
38     PS4 = PS3 + PS3;
39     PS4(23333);
40 
41     Console::WriteLine(L"-------------");
42     PS4 -= PS3;
43     PS4(233333);
44 
45     CClient1^ oC1 = gcnew CClient1();
46     CClient2^ oC2 = gcnew CClient2();
47 
48     DOperation^ DOp;
49     DOp = gcnew DOperation(oC1, &CClient1::DoubleNum)+gcnew DOperation(oC2,&CClient2::DDoubleNum);
50 
51     for each (DOperation^ dop in DOp->GetInvocationList())
52     {
53         Console::WriteLine(dop(666));
54     }
55 
56     return 0;
57 }

   .net的事件

    发布-订阅 机制

    基于委托

      事件只能由声明它的类型引发

      客户端只能用+=和-=来增删事件处理函数,不能用=重置调用列表

    事件源声明委托

    事件接收者提供适当方法

    方法绑定到委托

    事件发生调用委托进而调用方法

 1 #include "stdafx.h"
 2 
 3 using namespace System;
 4 
 5 //////////////////////////////////////////////////////////////////////////
 6 delegate void FristEventHandler(String^);
 7 delegate void SecondEventHandle(String^);
 8 
 9 ref class EventSrc
10 {
11 public:
12     event FristEventHandler^ OnFirstEvent;
13     event SecondEventHandle^ OnSecondEvent;
14 
15     void RaiseOne(String^ msg) { OnFirstEvent(msg); }
16     void RaiseTwo(String^ msg) { OnSecondEvent(msg); }
17 };
18 //////////////////////////////////////////////////////////////////////////
19 ref class EventReceiver
20 {
21 public:
22     EventReceiver(EventSrc^ esrc)
23     {
24         if (esrc==nullptr)
25         {
26             throw gcnew ArgumentException(L"Must have event source");
27         }
28 
29         m_EventSrc = esrc;
30 
31         m_EventSrc->OnFirstEvent += gcnew FristEventHandler(this, &EventReceiver::DoforFirstEvent);
32         m_EventSrc->OnSecondEvent += gcnew SecondEventHandle(this, &EventReceiver::DoforSecondEvent);
33     }
34 
35     void RemoveHandler()
36     {
37         m_EventSrc->OnFirstEvent -= gcnew FristEventHandler(this, &EventReceiver::DoforFirstEvent);
38     }
39 
40     void DoforFirstEvent(String^ msg) { Console::WriteLine(L"[Eventreceiver] event one,message {0}", msg); }
41     void DoforSecondEvent(String^ msg) { Console::WriteLine(L"[Eventreceiver] event two,message {0}", msg); }
42 
43 private:
44     EventSrc^ m_EventSrc;
45 };
46 
47 int main(array<System::String ^> ^args)
48 {
49     EventSrc^ src = gcnew EventSrc();
50     EventReceiver^ recvr = gcnew EventReceiver(src);
51 
52     src->RaiseOne(L"Hahaha");
53     src->RaiseTwo(L"blablabla");
54 
55     Console::WriteLine();
56     recvr->RemoveHandler();
57 
58     src->RaiseOne(L"Hahaha");
59     src->RaiseTwo(L"blablabla");
60 
61     return 0;
62 }
63  

   标准事件 System::EventHandler

    签名  delegate void EventHandler(System::Object^ sender, System::EventArgs^ e)

    建议使用标准事件

      直接使用System::EventHandler

 1 #include "stdafx.h"
 2 
 3 using namespace System;
 4 
 5 //////////////////////////////////////////////////////////////////////////
 6 ref class CCounter
 7 {
 8 public:
 9     CCounter(int nLimit)
10     {
11         m_nCounter = 0;
12         m_nLimit = nLimit;
13     }
14 
15     event EventHandler^ LimitReached;
16 
17     void Increment()
18     {
19         Console::WriteLine(L"Count:{0}",++m_nCounter);
20 
21         if (m_nCounter % m_nLimit==0)
22         {
23             LimitReached(this, gcnew EventArgs());
24         }
25     }
26 
27 private:
28     int m_nCounter;
29     int m_nLimit;
30 };
31 
32 //////////////////////////////////////////////////////////////////////////
33 ref class CObserver
34 {
35 public:
36     static void Callme(Object^ src, EventArgs^ args)
37     {
38         Console::WriteLine(L"Limit reached");
39     }
40 
41     void CallmeBaby(Object^ src, EventArgs^ args)
42     {
43         Console::WriteLine(L"Oh,Honey!");
44     }
45 
46 };
47 
48 //////////////////////////////////////////////////////////////////////////
49 int main(array<System::String ^> ^args)
50 {
51     //////////////////////////////////////////////////////////////////////////
52     CCounter^ oCounter=gcnew CCounter(5);
53 
54     //////////////////////////////////////////////////////////////////////////
55     oCounter->LimitReached += gcnew EventHandler(&CObserver::Callme);
56     
57     for (int i = 0;i<11;i++)
58     {
59         oCounter->Increment();
60     }
61 
62     //////////////////////////////////////////////////////////////////////////
63     //oCounter->LimitReached -= gcnew EventHandler(&CObserver::Callme);
64     //////////////////////////////////////////////////////////////////////////
65     
66     CObserver^ oObserver=gcnew CObserver();
67 
68     oCounter->LimitReached += gcnew EventHandler(oObserver, &CObserver::CallmeBaby);
69 
70     for (int i = 0;i < 11;i++)
71     {
72         oCounter->Increment();
73     }
74 
75     return 0;
76 }

=======================================================================

第十五章  .NET Framework类库

  鼓吹.NET的一章,泛泛草草的说了几页,意思大概就是之前的十四章都看完了,接着往下看吧,好戏才刚开始呢。

=======================================================================

第Ⅱ部分也没难度,只是容易忘、记不住。

=======================================================================

说说书上的错误吧

Page75 6.5 在类中使用常量

第一个小圆点· “它的值对于Card的所有实例来说都是4”,很显然英文拼错了,正确是“Car”


Page174 12.3.1 初始化
一共有三行代码,第二行的代码不能有(),应该改为array<int>^ intArray=gcnew array<int>{1,2,3};

Page207 14.2.2 使用MulticastDelegate

“而对于MutlcastDelegate,可使用……”中的英文显然拼错了,正确是“MulticastDelegate”

=======================================================================

再说说一点瑕疵

Page195 13.2.4 属性、继承和接口

在练习中给出的托管类定义,ref的前面是不需要public的,至少在这个例子和当前的教学上下文是不需要的。

=======================================================================

有空开始看第Ⅲ部分

原文地址:https://www.cnblogs.com/wlsandwho/p/4713311.html