Java開發者使用C++寫程式踩的坑

godoforange發表於2019-05-29

筆者是一個很矛盾的人。平時用Java。但是一開始學習的時候學的是組合語言,而且對C語言也很熟悉。為什麼不學C++呢?是因為我可以完全用Java的編碼規範去寫C++。因此我不需要了解更多的諸如C++的名稱空間,操作符重構,友元函式,多繼承這些更復雜的特性。

雖然C++介於Java和C之間,我並不需要學C++(開發用Java,指令碼用ruby,python,JavaScript)、但是作為一個計算機從業人員。不瞭解C++有點說不過去。

首先我先總結這次我學習C++的特性:(參考資料:菜鳥教程)

一、using namespace std

第一個讓我疑惑的是using namespace std;

話說回來這個是什麼意思?

當我對比了下Java檔案的命名規範(類名=檔名.java),我就懂了。

使用Java開發的人都明白一個道理、當你import 一個類的時候,Java 的包名.類名的檔案定義,而且一切皆物件,會使你不會遇到諸如C++名稱空間的這種錯誤。

例如你在標頭檔案中定義一個函式,這個函式如果被別人又定義了,在編譯時會報錯的。因此C++語言加了個名稱空間的語言特性。

有的同學可能問了,如果函式名重複了話,可以重構啊,。。。但是要是引數都一樣呢?

所以C++會用這種方式,定義了一個解決問題的方法。

下面是別人總結的。

名稱空間(namespace)是一種描述邏輯分組的機制,可以將按某些標準在邏輯上屬於同一個集團的宣告放在同一個名稱空間中。

原來C++識別符號的作用域分成三級:程式碼塊({……},如複合語句和函式體)、類和全域性。現在,在其中的類和全域性之間,標準C++又新增了名稱空間這一個作用域級別。

名稱空間可以是全域性的,也可以位於另一個名稱空間之中,但是不能位於類和程式碼塊中。所以,在名稱空間中宣告的名稱(識別符號),預設具有外部連結特性(除非它引用了常量)。

在所有名稱空間之外,還存在一個全域性名稱空間,它對應於檔案級的宣告域。因此,在名稱空間機制中,原來的全域性變數,現在被認為位於全域性名稱空間中。

標準C++庫(不包括標準C庫)中所包含的所有內容(包括常量、變數、結構、類和函式等)都被定義在名稱空間std(standard標準)中了。

 

std又是什麼呢? std是標頭檔案<iostream>中的一個名稱空間。包含了cin cout endl等函式。

using 指的是用這個名稱空間的函式。

具體使用如下:

#include <iostream>
using namespace std;
    
// first name space
namespace first_space{
    void func(){
        cout << "Inside first_space" << endl;
    }
}
    
// second name space
namespace second_space{
    void func(){
        cout << "Inside second_space" << endl;
    }
}
    
int main () {
     
// Calls function from first name space.
first_space::func();
       
// Calls function from second name space.
second_space::func(); 
    
return 0;
} 

 

二、類Class的定義

C++除了支援C語言中的結構體struct外,還支援class。

C語言中的struct裡面不能放方法、但是C++可以。

很多時候class和struct的差別其實不大。好像在預設訪問許可權和繼承方式有所不同,其餘的我也沒看到什麼新特徵。

不過C++與Java的區別在於C++可以在定義類之後,在其他地方定義方法。這個在Java裡面是不行的。Java不可以這樣。(別跟我說過載)

 

具體的實現如下:

#include <iostream>
 
using namespace std;
 
class Box
{
   public:
      double length;   // 長度
      double breadth;  // 寬度
      double height;   // 高度
};
 
int main( )
{
   Box Box1;        // 宣告 Box1,型別為 Box
   Box Box2;        // 宣告 Box2,型別為 Box
   double volume = 0.0;     // 用於儲存體積
 
   // box 1 詳述
   Box1.height = 5.0; 
   Box1.length = 6.0; 
   Box1.breadth = 7.0;
 
   // box 2 詳述
   Box2.height = 10.0;
   Box2.length = 12.0;
   Box2.breadth = 13.0;
 
   // box 1 的體積
   volume = Box1.height * Box1.length * Box1.breadth;
   cout << "Box1 的體積:" << volume <<endl;
 
   // box 2 的體積
   volume = Box2.height * Box2.length * Box2.breadth;
   cout << "Box2 的體積:" << volume <<endl;
   return 0;
}

同時,類的繼承和Java也有區別,他這個居然直接+:就好了,,,呵呵呵

在派生類(繼承類)中的使用如下

#include <iostream>
 
using namespace std;
 
// 基類
class Shape 
{
   public:
      void setWidth(int w)
      {
         width = w;
      }
      void setHeight(int h)
      {
         height = h;
      }
   protected:
      int width;
      int height;
};
 
// 派生類
class Rectangle: public Shape
{
   public:
      int getArea()
      { 
         return (width * height); 
      }
};
 
int main(void)
{
   Rectangle Rect;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
 
   // 輸出物件的面積
   cout << "Total area: " << Rect.getArea() << endl;
 
   return 0;
}

還有關於多型的問題,和Java差不多。這個我沒有特別細究。應該沒什麼區別吧。。

多型的示例程式如下:

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape{
   public:
      Rectangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
      { 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};
class Triangle: public Shape{
   public:
      Triangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
      { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};
// 程式的主函式
int main( )
{
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);
 
   // 儲存矩形的地址
   shape = &rec;
   // 呼叫矩形的求面積函式 area
   shape->area();
 
   // 儲存三角形的地址
   shape = &tri;
   // 呼叫三角形的求面積函式 area
   shape->area();
   
   return 0;
}

Java的抽象函式和介面在C++裡面也有體現

對應的叫虛擬函式。

虛擬函式 是在基類中使用關鍵字 virtual 宣告的函式。在派生類中重新定義基類中定義的虛擬函式時,會告訴編譯器不要靜態連結到該函式。

我們想要的是在程式中任意點可以根據所呼叫的物件型別來選擇呼叫的函式,這種操作被稱為動態連結,或後期繫結

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      // pure virtual function
      virtual int area() = 0;
};

然後子類繼承後,就順利的過載。

介面的話,就是完完全全的那種純虛擬函式。

像這種的

class Box
{
   public:
      // 純虛擬函式
      virtual double getVolume() = 0;
   private:
      double length;      // 長度
      double breadth;     // 寬度
      double height;      // 高度
};

三、模板

在Java裡面沒有模板的概念。那個叫泛型。在集合類,容器類等等應用十分廣泛。但是C++這裡不知道為啥又叫模板又叫泛型。。管他呢反正都是一個東西。

定義的如下

template <class type> ret-type func-name(parameter list)
{
   // 函式的主體
}

具體的實現如下

#include <iostream>
#include <string>
 
using namespace std;
 
template <typename T>
inline T const& Max (T const& a, T const& b) 
{ 
    return a < b ? b:a; 
} 
int main ()
{
 
    int i = 39;
    int j = 20;
    cout << "Max(i, j): " << Max(i, j) << endl; 
 
    double f1 = 13.5; 
    double f2 = 20.7; 
    cout << "Max(f1, f2): " << Max(f1, f2) << endl; 
 
    string s1 = "Hello"; 
    string s2 = "World"; 
    cout << "Max(s1, s2): " << Max(s1, s2) << endl; 
 
   return 0;
}

 

這樣就實現了類似於Java中的集合類的方法。

四、操作符的過載

過載這個我是真感覺C++太自由了。

也許C++本就不是為工程而設計的。

而是為一群真正的計算機愛好者定製的。

Java除了String 貌似別的都不行。哈哈

過載的運算子是帶有特殊名稱的函式,函式名是由關鍵字 operator 和其後要過載的運算子符號構成的。與其他函式一樣,過載運算子有一個返回型別和一個引數列表。

像這樣:

#include <iostream>
using namespace std;
 
class Box
{
   public:
 
      double getVolume(void)
      {
         return length * breadth * height;
      }
      void setLength( double len )
      {
          length = len;
      }
 
      void setBreadth( double bre )
      {
          breadth = bre;
      }
 
      void setHeight( double hei )
      {
          height = hei;
      }
      // 過載 + 運算子,用於把兩個 Box 物件相加
      Box operator+(const Box& b)
      {
         Box box;
         box.length = this->length + b.length;
         box.breadth = this->breadth + b.breadth;
         box.height = this->height + b.height;
         return box;
      }
   private:
      double length;      // 長度
      double breadth;     // 寬度
      double height;      // 高度
};
// 程式的主函式
int main( )
{
   Box Box1;                // 宣告 Box1,型別為 Box
   Box Box2;                // 宣告 Box2,型別為 Box
   Box Box3;                // 宣告 Box3,型別為 Box
   double volume = 0.0;     // 把體積儲存在該變數中
 
   // Box1 詳述
   Box1.setLength(6.0); 
   Box1.setBreadth(7.0); 
   Box1.setHeight(5.0);
 
   // Box2 詳述
   Box2.setLength(12.0); 
   Box2.setBreadth(13.0); 
   Box2.setHeight(10.0);
 
   // Box1 的體積
   volume = Box1.getVolume();
   cout << "Volume of Box1 : " << volume <<endl;
 
   // Box2 的體積
   volume = Box2.getVolume();
   cout << "Volume of Box2 : " << volume <<endl;
 
   // 把兩個物件相加,得到 Box3
   Box3 = Box1 + Box2;
 
   // Box3 的體積
   volume = Box3.getVolume();
   cout << "Volume of Box3 : " << volume <<endl;
 
   return 0;
}

總結

我真心覺得很多學生說C++難不是因為C++真的難,而是這種高自由的語法,很難讓一個初學者學生去掌握。對於學生來說最好先規範計算機的思維然後再學習C++,同時推薦大家去學Java。找工作簡單,語言簡單。

而要說精通C++我覺得至少要把GCC 或者Clang 都學個精通才算精通吧。畢竟語言的使用只是語言的一部分。

 

相關文章