目录
摘要
本文概述了C++/CLI面向对象编程的其余特性,如继承、接口和多态性。我们将通过在 CLR 执行模型下应用 C++/CLI 语义,详细了解各种控制语句,例如 if、while 和 do-while 构造以及其他不同的循环构造,例如 for 循环和开关构造。除此之外,我们还将面临其他重要概念,例如异常处理、内存管理、委托和泛型。最后,本文演示如何在 CLR 上下文中将本机 C++ 代码的实现与托管 C++/CLI 代码混合使用。
1、控制语句
控制语句定义应从给定语句执行哪些代码。C++/CLI 建议 if/else、条件运算符和 Switch 构造作为控制语句。if/else 构造语法与 C# 编码非常相似,如下所示。
- #include "stdafx.h"
- using namespace System;
- int main(array<System::String ^> ^args)
- {
- wchar_t ltr;
- Console::WriteLine("Enter the Letter");
- ltr= Console::Read();
- if (ltr >='a')
- if(ltr<='z')
- {
- Console::WriteLine("you have entered small Letter");
- }
- if (ltr >='A')
- if(ltr<='Z')
- {
- Console::WriteLine("you have entered capital Letter");
- }
- return 0;
- }
C++/CLI 中的条件运算符称为三元运算符。第一个参数必须是布尔值结果;如果结果为 true,则计算第一个表达式;否则,第二个是,如下所示:
- String^ str= i>5 ? "India" : "USA";
开关构造与 C# 非常相似,但不同之处在于 C++/CLI 不支持大小写选择中的字符串。相反,我们需要使用 if/else 结构。以下是此构造的简单示例:
- wchar_t days;
- Console::WriteLine("1 = Sunday");
- Console::WriteLine("2 = Monday");
- Console::WriteLine("3 = Tuesday");
- Console::WriteLine("Enter your choice");
- days= Console::Read();
- switch(days)
- {
- case '1': Console::WriteLine("Sunday");
- break;
- case '2': Console::WriteLine("Monday");
- break;
- case '3': Console::WriteLine("Tuesday");
- break;
- default: Console::WriteLine("Out of Reach");
- break;
- }
2、循环构造
C++/CLI 为每个循环构造定义 while 和 do-while 循环构造。使用循环时,代码会重复执行,直到满足条件。for、while 和 do-while 构造在语法上类似于 C#,如下所示:
- //for loop
- for(int i=0;i<5;i++)
- {
- //statements
- }
- //while loop
- int x=0;
- while(x<3)
- {
- //statements
- }
- //do-while loop
- do
- {
- //statements
- }while(i<3);
- array<int>^ arry= {1,2,3,4,5};
- foreach(int x in arry)
- {
- Console::WriteLine(x);
- }
3、数组
C++/CLI 引入了一个数组关键字来实现数组。此关键字使用带有尖括号的通用语法。尖括号用于定义元素的类型。C++/CLI 支持与 C# 语法相同的数组初始值设定项。
- #include "stdafx.h"
- using namespace System;
- int main(array<System::String ^> ^args)
- {
- //Array Declaration
- array<int>^ a1={ 10,20,30,40,50 };
- for each(int i in a1)
- {
- Console::WriteLine(i);
- }
- Console::ReadLine();
- return 0;
- }
4、静态成员
可以通过 static 关键字定义,这与 C# 非常相似。对于该类型的所有对象,静态字段仅实例化一次。我们不需要实例化类来访问静态成员。相反,我们可以使用类类型名称后跟 “::” 运算符 as 直接访问它们(就像在 C# 中使用 “.” 运算符一样)。
- #include "stdafx.h"
- using namespace System;
- public ref class test
- {
- public:
- static int i;
- test()
- {
- i++;
- Console::WriteLine("Constructor Called :{0}",i);
- }
- };
- int main(array<System::String ^> ^args)
- {
- test^ obj=gcnew test();
- test^ obj1=gcnew test();
- //directly access of static member
- Console::WriteLine(test::i);
- Console::Read();
- return 0;
- }
5、接口
interface 关键字用于定义接口。在 C++/CLI 中定义接口类似于 C# 语言,但实现略有不同。接口中定义的方法必须在子类中使用 virtual 关键字实现,如下所示:
- public interface class IDisplay
- {
- void hello();
- };
- public ref class test: IDisplay
- {
- public:
- virtual void hello()
- {
- Console::WriteLine("Hello test");
- }
- };
6、继承
继承是一种机制,在该机制中,可以在其相应的派生类中访问基类成员。默认情况下,所有 C++/CLI 类都是派生类。这是因为 value 类和引用类都具有标准基类 System::Object。在派生类中,基类应后跟冒号 (:)如下所示:
- public ref class baseClass
- {
- public:
- virtual void showBase()
- {
- Console::WriteLine("base class");
- }
- };
- public ref class test : baseClass
- {
- public:
- void showDerived()
- {
- Console::WriteLine("derieved class");
- }
- };
- int main(array<System::String ^> ^args)
- {
- test^ t=gcnew test();
- t->showBase();
- t->showDerived();
- return 0;
- }
访问修饰符描绘了继承中的重要角色,以防止程序集内部或外部的成员进行访问。
7、抽象类
用于实现 C++ 等效的纯虚函数。抽象类由 abstract 关键字定义,该关键字阻止您创建该类类型的对象。与接口不同,我们可以在抽象类中定义函数的实现(主体)。多态方法实现必须在派生类中使用 override 关键字进行标记,如下所示:
- #include "stdafx.h"
- using namespace System;
- public ref class absClass abstract
- {
- public:
- virtual double square(int x) abstract;
- virtual void show()
- {
- Console::WriteLine("showing you in abstract class");
- }
- };
- public ref class test : absClass
- {
- public:
- virtual double square(int x) override
- {
- return x*x;
- }
- virtual void show() override
- {
- Console::WriteLine("showing you in derived class");
- }
- };
- int main(array<System::String ^> ^args)
- {
- test^ t=gcnew test();
- Console::WriteLine("square is= {0}",t->square(20));
- t->show();
- Console::Read();
- return 0;
- }
8、异常处理
C++/CLI 定义了 try、catch、throw 和 finally 关键字来处理代码段中的所有运行时错误。异常处理实现与其他 CLR 支持的语言非常相似。下面的示例通过使用异常处理来处理数组越界错误。
- int main(array<System::String ^> ^args)
- {
- array<int>^ arry= {1,2,3};
- try
- {
- for(int i=0;i<=arry->Length;i++)
- {
- Console::WriteLine(arry[i]);
- }
- }
- catch(Exception^ ex)
- {
- Console::WriteLine(ex);
- }
- finally
- {
- Console::WriteLine("Exection Done");
- }
- Console::Read();
- return 0;
- }
前面的示例引发由 try/catch 块处理的运行时异常,如下所示:
9、委托
委托是指向方法的特殊类型安全指针。它们由 C++/CLI 语言中的 delegate 关键字定义,如下所示:
- #include "stdafx.h"
- using namespace System;
- //delegate definition
- public delegate void testDel(int z);
- public ref class test
- {
- public:
- void square(int x)
- {
- Console::WriteLine("Square is=",x*x);
- }
- };
- int main(array<System::String ^> ^args)
- {
- test^ t=gcnew test();
- testDel^ td=gcnew testDel(t,&test::square);
- td(2);
- Console::Read();
- return 0;
- }
10、泛型函数
似乎执行与 C++ 函数模板相同的操作。泛型函数规范本身是编译的,当您调用与泛型函数规范匹配的函数时,实际类型将在执行时替换类型参数。编译时不会生成额外的代码。
为了定义委托,C++/CLI 使用类似 C++ 的尖括号,使用类型参数,在调用函数时替换为实际类型,如下所示。
- #include "stdafx.h"
- using namespace System;
- generic<typename T> where T:IComparable
- T MaxElement(array<T>^ x)
- {
- T max=x[0];
- for(int i=1; i< x->Length; i++)
- {
- if(max-> CompareTo(x[i]) < 0)
- {
- max=x[i];
- }
- }
- return max;
- }
- int main(array<System::String ^> ^args)
- {
- array<int>^ iData= {3, 20, 4, 12, 7, 9};
- int maxI= MaxElement(iData);
- Console::WriteLine("Max Integer is={0}",maxI);
- array<double>^ dData= {4.2, 2.12, 25.7,1.1};
- double maxD= MaxElement(dData);
- Console::WriteLine("Max Double is={0}",maxD);
- Console::Read();
- return 0;
- }
前面的示例使用未定义类型的泛型函数从数组中生成最大数字。相反,类型(如整数或双精度)在执行期间定义,如下所示。
11、资源管理
C++/CLI 代码通过定义隐式调用 IDisposable 接口的析构函数来清理内存资源。
- public ref class test
- {
- public:
- ~test()
- {
- // release resources code
- }
- };
C# using 语句在不再使用资源后立即释放资源。编译隐式创建一个 try/finally 语句,并在 finally 块中调用 Dispose() 方法。C++/CLI 也提供了这种方法,但以更优雅的方式处理它,如下所示:
- public ref class test
- {
- public:
- void hello()
- {
- Console::WriteLine("Hello test");
- }
- };
- int main(array<System::String ^> ^args)
- {
- //Releasing resources
- {
- test t;
- t.hello();
- }
- Console::Read();
- return 0;
- }
12、本机代码和托管代码混合
C++/CLI 允许将本机 C++ 代码与 CLR 托管代码混合使用,从而提供了很大的优势。这个术语在 C++/CLI 中被称为“它只是工作”。以下示例通过调用本机 C++ iostream 命名空间的 cout 方法演示混合代码,如下所示:
- #include "stdafx.h"
- #include <iostream>
- using namespace System;
- public ref class test
- {
- public:
- void managedCode()
- {
- Console::WriteLine("Hello test");
- }
- //Native code funtion calling
- void nativeCode()
- {
- std::cout << "native code sample";
- }
- };
- int main(array<System::String ^> ^args)
- {
- //Releasing resources
- {
- test t;
- t.managedCode();
- t.nativeCode();
- }
- return 0;
- }
总结
本文通过定义数组、控制语句、泛型、委托和条件语句的语义,详细概述了其他重要主题。我们还通过一些示例来理解 C++/CLI OOP 概念,例如接口、多态性和继承。完成本系列文章后,人们能够有效地用 C++/CLI 编写代码。