C++/CLI for C# programmer使用基本指南
该文涉及的内容如下:
- C++基本语法
- VS中创建C++项目
- VS C++项目属性介绍
- C++/CLI介绍
- VS中创建C++/CLI项目
C++基本语法
// cppclass.h
#ifndef _CPP_CLASS_H_
#define _CPP_CLASS_H_
#include <string> // 使用include包含头文件
namespace MyClassSpace // 定义命名空间
{
class BaseClass // 定义一个类
{
public: // 声明共有部分
BaseClass(); // 构造函数
BaseClass(const std::string& name);
~BaseClass(); // 析构函数
void PrintClassName(); // 类成员函数
virtual void Execute(); // 类成员虚函数
private: // 声明私有部分
std::string m_name; // 成员变量
};
class ChildClass : public BaseClass // 继承一个类
{
public:
ChildClass();
ChildClass(const std::string& name);
~ChildClass();
virtual void Execute();
};
}
#endif
// cppclass.cpp
#include "cppclass.h"
#include <iostream>
namespace MyClassSpace
{
BaseClass::BaseClass() // 构造函数实现
{
m_name = "base class";
}
BaseClass::BaseClass(const std::string& name) // 构造函数实现
{
m_name = name;
}
BaseClass::~BaseClass() // 析构函数实现
{
}
void BaseClass::PrintClassName()
{
std::cout << "This class name is " << m_name << std::endl;
}
void BaseClass::Execute()
{
std::cout << "BaseClass::Execute" << std::endl;
}
ChildClass::ChildClass() // 构造函数,利用了基类的构造
: BaseClass("child class")
{
}
ChildClass::ChildClass(const std::string& name)
: BaseClass(name)
{
}
ChildClass::~ChildClass()
{
}
void ChildClass::Execute()
{
std::cout << "ChildClass::Execute" << std::endl;
}
}
// main.cpp
#include "cppclass.h"
using namespace MyClassSpace; // 使用命名空间
int main() // 可执行程序的入口
{
const int arraySize = 2; // 常量定义
BaseClass* classArray[arraySize]; // 指针的数组定义
for (int i=0; i<arraySize; ++i) // 循环
{
if (i == 0) // 条件判断
{
classArray[i] = new BaseClass(); // new一个实例
}
else
{
classArray[i] = new ChildClass(); // new一个实例
}
}
// 输出的结果如下:
// This class name is base class
// BaseClass::Execute
// This class name is child class
// ChildClass::Execute
for (int i=0; i<arraySize; ++i)
{
classArray[i]->PrintClassName();
classArray[i]->Execute();
}
// 注意new出来的对象注意释放掉
for (int i=0; i<arraySize; ++i)
{
if (classArray[i])
{
delete classArray[i]; // 释放new出来的对象
classArray[i] = nullptr;
}
}
return 0; // 函数返回值
}
VS中创建C++项目
- VS2010,File->New Project,选择Empty Project,填写name,如下图:
- 将上一节中的代码添加到该工程中
- 编译运行即可
VS C++常用项目属性介绍
通用属性
- Configuration: Active(Debug). 通常用来设定目标构建出来是Debug的还是Release的。该值可以在Configuration Manager中进行设定
- Platform: Active(Win32). 同来设定目标构建出来的是基于32bit平台还是64bit平台的。该值可以在Configuration Manager中进行设定
- General: 一些通用的设置,包括:
- 输出目录
- 中间结果的输出目录
- 目标名字
- 扩展
- Configuration Type: exe,dll,or lib。
- Use of MFC:是否需要使用MFC相关的库,通常不需要
- Use of ATL: ATL介绍,通常也不需要
- Character Set:
Use Multi-Byte Character Set
orUse Unicode Character Set
,这个指的是,源代码编译成二进制的时候采用的编码,为内存编码。Unicode:一种所有字符都是用两个字节编码的编码模式;Multi-Byte:字节长度不是固定的。 - Common Language Runtime Support: 是否使用通用语言运行时支持,在CLI一节中会给出介绍
- Whole Program Optimization: 全局项目优化。
Debugging
此时需要关注的主要是Command,Command Arguments, Working Directory三项。
- Command指的是exe程序,如果工程生成的就是exe可执行文件,那么该项就默认为
$(TargetPath)
,如果生成的是dll程序,那么需要调试的时候,需要将该项设置成为载入当前dll的可执行文件。 - Command Arguments:指的是可执行文件需要传入的参数
- Working Directory:指的是可执行文件的工作目录,工作目录没有设置正确,启动调试的时候加载依赖的dll,可能会出错
C/C++ General
- Additional Include Directories: 设置外部依赖的include文件的目录
- Resolve #using Reference: 当使用clr进行编译的时候,用来指定
#using "some.dll"
的目录 - Debug Information Format:
- /Z7: 生成的obj文件中包含所有的debug information,不会生成pdb文件;
- /Zi:生成pdb文件来包含debug information,可以和
/Gm Enable minimal rebuild
一起使用,而/Z7
则不能; - /ZI:通常情况下不适用该选项
- Common Language Runtime Support:clr相关
- Suppress Startup Banner:在编译的时候显示或不显示版本信息
- Warning Level:通常情况下设置为/W4
- Treat Warnings As Errors: 通常情况下设置为Yes
- Multi-processor Compilation: 通常设置为Yes
- Use Unicode For Assembler Listing: 与输出的汇编相关,不清楚其用途。
C/C++ Optimization
- Optimization: 代码优化控制
- Inline Function Expansion、Enable Intristic Function:内联函数相关
- Favor Size Or Speed:优先选择大小还是速度
- Omit Frame Pointer:涉及到汇编相关的解释,详细内容请跳转,http://www.cnblogs.com/awpatp/archive/2009/11/04/1595988.html
- Enable Fiber-Safe Optimizations: 不是很清楚,感兴趣的可以参见: https://stackoverflow.com/questions/31042684/what-exactly-is-fiber-safe-optimizations-in-vc
- Whole Program Optimization: 整个程序的优化
一般情况下,上述的设置,保持默认即可。
C/C++ Preprocessor
- Preprocessor Definitions: 定义预定义的宏
#ifdef _TEST_
const bool test = true; // 1
#else
const bool test = false; // 2
#enif
针对于上面的示例代码,如果在该选项中,添加,_TEST_
,那么会执行逻辑1,否者执行逻辑2.
- Undefine Preprocessor Definitions: 与上面正好相反
其他相关属性一般保持默认
C/C++ Code Generation
- Enable String Pooling: 如果启用该属性,那么下面代码中s和t指向的是相同的内存空间。
char *s = "This is a character buffer";
char *t = "This is a character buffer";
- Enable Minimal Rebuild: 启用后,当对应的头文件发生变化时,使用该头文件的cpp源文件才会被重新编译
- Enable C++ Exceptions: 对于c++异常抛出的设定
- Runtime Library: 生成release下的dll用
/MD
,debug下的dll用/MDd
,relase下的exe用/MT
,debug下的exe用/MTD
C/C++ Advanced
- Calling Convention: 函数调用约定,如果在使用第三方库的时候,两边的函数调用约定不同,那么生成的程序在运行的时候,可能会报第三方库调用到的函数堆栈异常的错误。具体见: https://blog.csdn.net/cnhk1225/article/details/53115381
- Disable Specific Warnings: 用来屏蔽特定的警告
Linker General
- Additional Library Directories: 额外的lib目录
Linker Input
- Additional Dependencies:用来设定依赖的lib文件
Linker Debugging
- Generate Debug Info: 是否需要产生debug信息,如果为false,那么在调试的时候由于找不到对应的debug相关的信息,就没法进行调试,如断点设置等。
Linker Advanced
- Import Library: 如果生成的是dll,如果需要将dll对应的lib文件输出到另外的文件夹中,那么就需要设定这个值。如
..$(TargetName).lib
Build Events
如果在程序进行build之前或之后需要执行一些命令,可以在这个选项中进行添加,如,在程序执行之前,生成proto对应的头文件和源文件等。
C++/CLI介绍
什么是C++/CLI
C++/CLI的链接
上图实现cli编译的obj文件和非cli编译的目标文件之间实现链接。
上图实现cli编译的obj文件和lib文件之间进行链接
上图实现cli编译的代码对非cli编译的dll的引用
C++/CLI基本语法
- 基本类型
从上表中可以发现,在C#里面不同命令空间,或类成员的方位使用的是.
,在CLI中使用的是::
。
- 托管内存
托管内存受到垃圾收集器进行释放管理。托管堆内存的申请使用关键字gcnew
,如:System::String^ name = gcnew System::String(L'a', 10)
,此处需要注意的是非托管类型不能使用gcnew
来申请托管内存。在纯粹的c++中,指针对象是使用星号*
标识,此处gcnew
的到的对象是用^
进行标识的。同时关键字nullptr
也能够直接赋值给nameSystem::String^ name=nullptr;
。
- System::String
System::String的操作与c#中String的操作基本保持一致。
String^ str = string::Empty;
str1 += "a";
str1 = str1 + "a";
str1 = String::Concat(str1, "a");
String^ str2 = str1->ToUpper();
- Managed Arrays
二维数组的定义如下:
array<int,2>^ arr = gcnew array<int,2>(2,2);
arr[0,0] = 1; arr[0,1] = 2;
arr[1,0] = 3; arr[1,1] = 4;
// managed type的对象数组
// array<System::String> a; 这种实现方式是非法的,应该为
array<System::String^> a;
- Stream-Based IO
// Read bytes from file
FileStream^ fs = gcnew FileStream("SampleFile.txt", FileMode::Open);
int bytesInFile = fs->Length;
array<Byte>^ bytes = gcnew array<Byte>(bytesInFile);
fs->Read(bytes, 0, bytesInFile);
String^ textInFile = Encoding::ASCII->GetString(bytes);
- Managed Exception Handling
StreamReader^ sr = gcnew StreamReader(arg);
try
{
TextWriter^ tw = Console::Out;
tw->WriteLine("File {0}", arg);
DumpTextReader(sr, tw);
}
catch (Exception^ exc)
{
// Do something
throw;
}
finally
{
sr->Close();
}
- Casting Managed Types
WebRequest^ req = GetWebRequestFromSomWhere();
if (dynamic_cast<FtpWebRequest^>(req) != nullptr)
{
;
}
- 自定义common type system(CTS)类型
// 此处使用ref class替代class
ref class ManagedReferenceType
{
int aPrivateField;
public:
void APublicFunction();
};
// 定义一个value type
public value class Point
{
int x;
int y;
public:
Point(int x, int y);
};
gcnew array<V>(100); // V: value type
gcnew array<R^>(100); // R: ref type
- initonly
这个关键字和c#中的readonly
的含义是相同的。
ref class MathConstants
{
public:
static initonly double Pi = 3.1415926; // 直接初始化
}
VS中创建C++/CLI项目
- 新建项目
- 常见项目属性设置
- Configuration Platform:选择平台,win32或者是x64
- General - 自定义输出目录
- C/C++ General: 设定额外的头文件目录
- Linker General:设定额外的lib库目录
- Linker Input:设置依赖的lib库
Other Resource
- <<Expert C++/CLI: .NET for Visual C++ Programmers>>