1. 程式人生 > 實用技巧 >C++/CLI for C# programmer使用基本指南

C++/CLI for C# programmer使用基本指南

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 or Use 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

一般情況下,上述的設定,保持預設即可。

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>>