日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
從C#到C++容易出現(xiàn)的問題解答

前言

最近在學(xué)習(xí)用c++寫一下3D引擎(廢話一下,叫做WuguiEngine,首先Wugui是我的外號(hào),也是代表這個(gè)引擎很粗糙,速度很慢,呵呵.之后等引擎成熟一點(diǎn)我再寫寫相關(guān)的一些文章).這幾天寫起來感覺c++好多地方和c#區(qū)別很大,這里大概寫寫這兩天碰到的一些問題,也許是從c#到c++的時(shí)候的一些通病,對(duì)c++ 新手也有一定的幫助.

另外在本文中,多數(shù)是將類拆分為.h文件和.cpp文件這樣對(duì)于工程來說更好管理.

另外閱讀本文需要一定的c++基礎(chǔ),本文主要是一些雜碎的心得,而不是完整的教學(xué),下面就開始解答從c#到c++的問題。

頭文件

頭文件是c#沒有的內(nèi)容,所以用好頭文件是學(xué)習(xí)c++首先需要解決的一個(gè)內(nèi)容.頭文件在正常的時(shí)候應(yīng)該是只放上定義,實(shí)現(xiàn)代碼應(yīng)該寫在同名的cpp文件里面

1) 重復(fù)包含:頭文件A.H被B.H與C.H同時(shí)包含,則在編譯的時(shí)候,A.H里面定義的代碼將被定義兩次,造成"Symbol already defined",在這種時(shí)候應(yīng)該在.H文件頭尾處加上下列的代碼就可以解決這個(gè)問題:

 
 
 
  1. #ifndef _NAME_H
  2.  #define _NAME_H
  3.  //add defination
  4. #endif

其實(shí)#ifndef與#define的內(nèi)容只要對(duì)于每個(gè).h文件是唯一的就好了.

 2)嵌套包含:在A.H(class A)中使用了class B,又在B.H(class B)中使用了class A,這個(gè)時(shí)候需要在類的前面加入前置定義,下面的代碼:

 
 
 
  1. #ifndef _A_H
  2.    #define _A_H
  3.     
  4.    #include "B.H"
  5.     
  6.    //前置聲明
  7.    class B; 
  8.     
  9.    class A
  10.    {
  11.       //add defination
  12.    }
  13.     
  14.    #endif

這點(diǎn)說明,頭文件并不能代替前置聲明,對(duì)于有namespace的情況,前置聲明更加復(fù)雜,下一小節(jié)將談?wù)勥@點(diǎn)內(nèi)容.

3)一些經(jīng)驗(yàn):

頭文件包含其實(shí)是一想很煩瑣的工作,不但我們看著累,編譯器編譯的時(shí)候也很累,再加上頭文件中常常出現(xiàn)的宏定義。感覺各種宏定義的展開是非常耗時(shí)間的,遠(yuǎn)不如自定義函數(shù)來得速度。我僅就不同頭文件、源文件間的句則結(jié)構(gòu)問題提出兩點(diǎn)原則,僅供參考:

第一個(gè)原則應(yīng)該是,如果可以不包含頭文件,那就不要包含了。這時(shí)候前置聲明可以解決問題。如果使用的僅僅是一個(gè)類的指針,沒有使用這個(gè)類的具體對(duì)象(非指針),也沒有訪問到類的具體成員,那么前置聲明就可以了。因?yàn)橹羔樳@一數(shù)據(jù)類型的大小是特定的,編譯器可以獲知。

第二個(gè)原則應(yīng)該是,盡量在CPP文件中包含頭文件,而非在頭文件中。假設(shè)類A的一個(gè)成員是是一個(gè)指向類B的指針,在類A的頭文件中使用了類B的前置聲明并便宜成功,那么在A的實(shí)現(xiàn)中我們需要訪問B的具體成員,因此需要包含頭文件,那么我們應(yīng)該在類A的實(shí)現(xiàn)部分(CPP文件)包含類B的頭文件而非聲明部分(H文件)。

第三個(gè)原則是(我自己覺得的):盡量對(duì)引用的其他的類都加上前置聲明.這樣不僅使得程序的結(jié)構(gòu)更加清楚,而且使得可以少出一些編譯錯(cuò)誤

namespace

 
 
 
  1.  #ifndef _BASEGAME_H
  2.  #define _BASEGAME_H
  3.   
  4.  namespace WuguiEngine
  5.  {
  6.      //前置聲明
  7.      class IUpdatable;
  8.   
  9.      //前置聲明
  10.     namespace Graphics
  11.     {
  12.         class GraphicsDevice;
  13.     }
  14.     
  15.     //前置聲明
  16.     namespace Core
  17.     {
  18.         class TimeUsed;
  19.     }
  20.  
  21.     //簡化的寫法,GraphicsDevice可以在下面的代碼中直接使用
  22.     //GraphicsDevice與WuguiEngine::Graphics::GraphicsDevice等價(jià)
  23.     //注意:如果不加上下面這行,WuguiEngine::Graphics不能省略
  24.     using Graphics::GraphicsDevice;
  25.  
  26.     class BaseGame : virtual public IDisposed, 
  27.         virtual public IRenderable
  28.     {
  29.         // add definition
  30.     }
  31. }
  32.  
  33. #endif

上面的代碼簡單的說明了namespace的一些基本的用法,該段代碼取自BaseGame.H的文件,在class BaseGame中,用到了來自不同的命名空間下的IUpdatable, GraphicsDevice等類.具體的內(nèi)容可以先看看代碼里面的注釋

在需要在BaseGame.H中包含這些類的頭文件的同時(shí),需要加上這些類的前置聲明,如果不加會(huì)出現(xiàn)一些詭異的編譯錯(cuò)誤(有些問題可能也是在于我比較不了解c++),反正我覺得使用using namespace ...并不是一個(gè)很好的做法,不如using XXX::YYY::ZZZ來得準(zhǔn)確(這里也希望高手來拍磚指點(diǎn)一下.

繼承

1)virtual繼承

在繼承接口(只具有純虛函數(shù)的類)的時(shí)候最好為繼承的方法加上virtual的說明(參考上面一段的代碼,IUpdatable與IDisposed就是接口,主要的原因是在于c++的多重繼承機(jī)制,假如A與B都繼承自IInterface,C又繼承自A,B,那么普通的繼承方式則會(huì)在C類中保存兩個(gè)IInterface的副本.

而virtual繼承就有區(qū)別了,virutal繼承告訴編譯器:"我繼承的是一個(gè)純接口!",這樣只會(huì)保存一個(gè)副本.

2)多種繼承方式

大家知道,C++對(duì)于繼承的方式有很多的修飾,有public, private, protected,而且還可以加入virtual關(guān)鍵字.在c++中,public繼承與在c#中的繼承是沒有區(qū)別的,而其他幾種繼承是具有理論的價(jià)值,而實(shí)際中的應(yīng)用得非常非常的少,這里就不再贅述了.

3)實(shí)驗(yàn):重寫虛函數(shù)

下面做一個(gè)簡單的實(shí)驗(yàn),看看c++與c#在重寫虛函數(shù)時(shí)候調(diào)用基類的虛函數(shù)的時(shí)候的情況,大家自己可以對(duì)比一下c#.測試代碼:

 
 
 
  1. #include < iostream>
  2.  using namespace std;
  3.    
  4.   class Base
  5.   {
  6.   public:
  7.       virtual void Func() { cout < <  "Hello Earth" < <  endl; }
  8.  };
  9.    
  10.  class Derived : public Base
  11.  {
  12.  public:
  13.      virtual void Func() { cout < <  "Hello World" < <  endl; }
  14.  };
  15.   
  16.  int main()
  17.  {
  18.      Base* p1 = new Base();
  19.      p1->Func();
  20.   
  21.      Base* p2 = new Derived();
  22.      p2->Func();
  23.  }

輸出:

              Hello Earth

              Hello World

而在將Base的Func()改為純虛函數(shù)之后,在Base* p1 = new Base()這句話上出現(xiàn)編譯錯(cuò)誤,提示不能實(shí)例化抽象類. 而對(duì)于p2的調(diào)用時(shí)正常的

下面繼續(xù)深入我們的實(shí)驗(yàn),三個(gè)類依次繼承,爺爺類具有一個(gè)純虛函數(shù),爸爸類什么都不寫,兒子類重寫該函數(shù),都使用virtual public繼承:

 
 
 
  1. #include < iostream>
  2.  using namespace std;
  3.   
  4.  class Base
  5.  {
  6.  public:
  7.      virtual void Func() = 0 ;
  8.   };
  9.    
  10.  class Derived : virtual public Base
  11.  {
  12.   
  13.  };
  14.   
  15.  class DerivedDerived : virtual public Derived
  16.  {
  17.  public:
  18.      virtual void Func() { cout < <  "Hello World" < <  endl; }
  19.  };
  20.   
  21.  int main()
  22.  {
  23.      Base* p1 = new DerivedDerived();
  24.      Derived* p2 = new DerivedDerived();
  25.   
  26.      p1->Func();
  27.      p2->Func();
  28.  }

輸出結(jié)果都是"Hello World"

今天也有點(diǎn)晚了,明天還要坐火車,從c#到c++的問題先寫到這里,各位晚安,歡迎提出意見 ????


網(wǎng)頁題目:從C#到C++容易出現(xiàn)的問題解答
標(biāo)題URL:http://www.5511xx.com/article/cdjogph.html