所有教程由网友发布,仅供参考,请谨慎采纳。科创不对教程的科学性、准确性、可靠性负责。
【教程】10分钟C++/CLI教程
acmilan2015/03/30软件综合 IP:四川
C++/CLI是C++的扩展,针对.NET Framework编程进行了增强设计,可以实现类似C#的功能,同时兼容原有的C++功能。
这篇文章针对已经学习过C++和C#的读者,主要介绍C++/CLI的增强特性,方便读者快速熟悉和掌握C++/CLI这种增强编程语言。

一、访问命名空间、静态类、对象成员的方法

对于命名空间和静态类成员,C++/CLI使用范围限定操作符::来访问,例如:
using namespace System::Windows::Forms; // 访问命名空间
System::Windows::Forms::Button ^button1; // 访问命名空间中的类
Console::WriteLine("错误:文件不存在!"); // 访问静态类成员

对于对象成员,C++/CLI使用->来访问,例如:
this->Text="控制面板自定义";
listBox1->Items->Add("简明DOS教程");

对于非引用对象(基本类型、原生类型、结构等),C++/CLI使用.运算符来访问,例如:
XXXXXXXXXXXXXString();

也可以混合使用:
System::Console::Error->WriteLine("错误代码:"+XXXXXXXXString());

二、.NET对象的使用

大多数.NET对象仅允许在堆中创建,在堆中创建的方法是使用.NET对象指针^和gcnew操作符。

C++/CLI使用^修饰符修饰.NET对象指针(官方称为对象句柄),使用方法和传统的指针*差不多,但是不允许运算,例如:
ListBox ^listBox1;
String ^str1;

对.NET对象指针解引用,使用*操作符,和C++指针一样,例如:
(*label1).Text="用户名";

C++/CLI使用gcnew操作生成新的.NET对象,其作用类似其它语言的new运算符,.NET有自动垃圾回收机制,不需要手动释放,例如:
this->listBox1 = gcnew ListBox();

对于变量的引用,使用%来表示,类似于C#中的ref修饰符,以及C++中的&修饰符,如:
void increase(int% val) { ... } // 引用传递
void trimstr(String^% str) { ... } // 对.NET对象引用传递

三、数组

不同于C#的简单语法,C++/CLI使用以下方法来定义数组:
array<int> ^intarray = gcnew array<int>{1, 2, 3}; // 预定义元素
array<String^> ^strarray = gcnew array<String^>(5); // 5个空元素

数组的访问:
for (int k=0; k<intarray.Length; k++) {
  MessageBox::Show(intarray[k].ToString());
}

四、字符串

C++/CLI使用以下方法来定义字符串:
String ^str1="我是字符串\n";
String ^str3=gcnew String("我是字符串\n");

String^和字符串常量均支持+运算符,并且字符串常量相加后自动转换为String^,如:
str1 = "发生错误!\n"+"错误代码:"+XXXXXXXXString();

将数据转换为字符串的方法:
String ^str2=String::Format("错误代码:{0} 错误消息:{1}",24,"未找到文件");
String ^str4=XXXXXXXXString();

将字符串转换为数字的方法:
int errno=Int32:: Parse(strerrno);
int errno=Convert::ToInt32(strerrno);

五、for each语法

ISO在C++11中加入了for遍历语法用以遍历集合元素,然而在C++/CLI中微软先行加入了这一语法,但是语法结构有所不同:
for each(int val in vals) { ... }  // 数值传递
for each(int% val in vals) { ... }  // 引用传递
for each(String^ msg in msglist) { ... }
for each(String^% str in strlist) { ... }

六、类语法

.NET类的定义如下,不同于传统C++类:
ref class MyClass [修饰符] : public BaseClass, IBaseInterface { ... };
.NET接口的定义如下:
interface class IMyInterface [修饰符] : public IBaseInterface { ... };
.NET结构定义如下:
value class MyStruct [修饰符] : public IBaseInterface { ... };
.NET枚举定义如下:
enum class MyEnum : basetype { ... };

class也可换成struct,区别只是默认访问权限不同,class默认是private而struct默认是public。
其中修饰符可以是abstractsealed,分别表示抽象类和不可派生类。

泛型(generic)语法如下,不同于C++模板(template):
generic <typename T>
ref class MyClass : public BaseClass,IBaseInterface { ... };

七、成员语法

成员虚函数可在最后加上.NET修饰符,如:
ref class B{ public:
virtual void f();
virtual void g() abstract; //纯虚函数,需要派生类重写,否则派生类就是纯虚类
virtual void h() sealed; //阻止派生类重写该函数
virtual void i();
};
ref class D : B { public:
virtual void f() new; //新版本的f,虽然名字和B::f相同,但是并没有重写B::f。
virtual void h() override; //错误!sealed函数不能被重写
virtual void k() = B::i; //“命名式”重写
};

析构函数和回收函数:
析构函数~ClassName()和C++中的析构函数相同,当出作用域时被调用,相当于C#中的Dispose()。
回收函数!ClassName()则相当于C#中的Finalize(),在系统真正delete时被调用,不能确定调用时机,不建议使用。
MyClass() { ... } // 构造函数
~MyClass() { ... } // 析构函数Dispose()
!MyClass() { ... } // 回收函数Finalize()

literal表示.NET常量,在编译时展开,总是静态成员,相当于C#中的const。
literal double MyPI=3.14;
circum = diameter * MyClass::MyPI;

initonly表示.NET只读成员,最多只能在构造函数初始化一次,相当于C#中的readonly。
initonly int PortNo=42;
initonly String^ FileName; // 只能在构造函数中初始化

property表示.NET属性,如:
property String ^FileName; // 纯数值属性
property String ^Text { // 自定义set和get方法
      void set(String^ value) { ... }
      String^ get() { ... }
}
property int Nums[int] { // 带有索引的.NET属性
      void set(int index, int value) { ... }
      int get(int index) { ... }
}

八、指针

在C++/CLI中,除了传统指针(*)和.NET对象指针(^)外,还增加了两种指针类型:pin_ptr(图钉指针)和interior_ptr(托管指针)。
由于.NET堆地址有自动垃圾回收机制,因此对象地址经常变动的,不便于普通指针使用。
当传统使用指针时需要先使用pin_ptr(图钉指针)钉住对象。而interior_ptr(托管指针)则封装了可变特性,可以和普通指针一样使用。

pin_ptr(图钉指针)可以钉住堆地址以供传统指针使用(但不是万能的):
array<char>^ arr = gcnew array<char>(3);
pin_ptr<char> p = &arr[0];   // 整个arr都被定在堆上
char* pbegin=p;  // 现在可以使用传统指针了

interior_ptr(托管指针)可以像传统指针一样使用:
array<char>^ arr = gcnew array<char>(3);
interior_ptr<char> begin = &arr[0]; //指向头部的指针
interior_ptr<char> end = begin + 3;  //注意,不能写&arr[3],会下标越界

指针的空值为nullptr,相当于C#中的null,对应传统C++中的NULL,未初始化的任何指针默认值都是nullptr,如:
ListBox ^listbox1; // 值为nullptr,下同
int *valptr;
pin_ptr<char> pinptr;
interior_ptr<char> chrptr;
listbox1 = nullptr; // 手动设置nullptr

九、delegate和event

作为.NET的增强特性,C++/CLI当然也不会缺少delegate。delegate相当于定义一个函数指针类型,但是比函数指针强大,如下:
delegate int MyDelegate(int num1, int num2);

delegate的使用方法:
MyDelegate ^del1 = gcnew MyDelegate(&fnstatic); // 绑定静态函数
MyDelegate ^del2 = gcnew MyDelegate(this, &MyClass::fnmember); // 绑定成员函数
result = del2(2, 3);

event则是.NET事件,实质上是一种特殊的.NET属性,如:
event MyDelegate ^ OnMyEvent1;
event MyDelegate ^ OnMyEvent2 {
      void add (MyDelegate ^ evt) { ... }
      void remove(MyDelegate ^ evt) { ... }
      int raise(int num1,int num2) { ... } // 必须和delegate定义相同
}

(完)

[修改于 9年2个月前 - 2015/03/30 15:00:11]

来自:计算机科学 / 软件综合严肃内容:教程/课程
1
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
acmilan 作者
9年2个月前 IP:四川
760058
看来这种糅合的语言不怎么优雅,也不怎么招人喜欢啊。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年4个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}