2015-05-01 77 views
0
#include <iostream> 
#include <string> 
using namespace std; 

class Part{ 
public: 
    std::string spec; 
    Part(std::string str){ 
     this->spec = str; 
    } 
    std::string getSpec(){ 
     return spec; 
    } 
}; 

class Car{ 
public: 
    Part getEngine(); 
    Part getWheels(); 
    Part getBody(); 
}; 


class Benz:public Car{ 
public: 
    Part getEngine(){ 
     return Part("Benz Engine"); 
    } 
    Part getWheels(){ 
     return Part("Benz Wheels"); 
    } 
    Part getBody(){ 
     return Part("Benz Body"); 
    } 
}; 

class Audi:public Car{ 
public: 
    Part getEngine(){ 
     return Part("Audi Engine"); 
    } 
    Part getWheels(){ 
     return Part("Audi Wheels"); 
    } 
    Part getBody(){ 
     return Part("Audi Body"); 
    } 
}; 

class CarFactory{ 
public: 
    Car *pcar; 
    Car *getCar(std::string carType){ 
     if (carType.compare("Benz") == 0){ 
      pcar = new Benz(); 
     }else if (carType.compare("Audi") == 0){ 
      pcar = new Audi(); 
     } 
     return pcar; 
    } 
}; 

int main(){ 
    CarFactory *cf = new CarFactory(); 
    Car *mycar = cf->getCar("Benz"); 
    Part myCarBody = mycar->getBody(); 
    cout <<myCarBody.getSpec() <<endl; 
    //cout << mycar->getBody().getSpec() <<endl; 
} 

在上面的代碼獲得,未定義的在參考線部分myCarBody = mycar-> getBody到對象錯誤();主功能線。你可以幫我固定這一點,也請解釋汽車* mycar和車mycar之間的差異。哪一個選擇什麼時候?未定義參照對象錯誤

感謝您的幫助。的Car

+0

'Car * mycar'是指向'Car'的指針; '汽車mycar'是一個實際的'汽車'對象。你需要在指針上使用箭頭(' - >')符號;你需要在對象中使用點('.')符號。在這種情況下,指針比對象更有可能是有益的。這往往是這樣,但並非總是如此。 –

+0

這段代碼中的繼承模型有很多不足之處。所有'Benz'對象都表現相同;所有的'奧迪'對象都表現相同。那很糟。這是古董,但湯姆嘉吉的書[C++編程風格](http://www.amazon.com/C-Programming-Style-Tom-Cargill/dp/0201563657)詳細討論了這個和其他一些常見問題。 –

+0

@Kranthi請接受任一答案。是時候了。 – LogicStuff

回答

6

成員函數應該是純虛,而不是你的非虛擬聲明:

class Car 
{ 
public: 
    virtual ~Car() = default;  // Virtual destructor 
    virtual Part getEngine() = 0; 
    virtual Part getWheels() = 0; 
    virtual Part getBody() = 0; 
}; 

這就是爲什麼連接錯誤。 編譯器預計Car的函數定義因爲這些功能不是純虛擬的,但它無法找到它。
隨着純虛擬成員函數,Car成爲一個抽象類和提供一個接口(純虛擬的),必須通過從它派生的類來實現。否則,派生類也將是抽象的,不可實例化。

通過調用基類的虛函數,你最終調用了派生類中的覆蓋的功能。 析構的情況也是如此,需要到進行虛擬,爲了調用派生類的析構函數並避免未定義的行爲。如果您在其中一個派生類中有動態分配的數據,則會出現內存泄漏。

此外,您必須使用指針或引用時處理多態性。其背後的邏輯是指針具有相同的大小,但派生類如Benz可能有額外的數據,並且不適合Car所佔用的空間,並且會變得切片。因此,如果沒有指針或引用,分配/複製結構將無法正常工作。

提出在評論:

  • 訪問函數( 「干將」 和 「二傳手」)通常會用 私有或受保護的成員。你的公開,訪問者是 沒用,可以繞過。保留訪問者,使數據 私有。當你回來的一員,您可以通過 引用給const做到這一點。但是不要爲getEngine,getWheelsgetBody這樣做,因爲它們返回的是本地對象而不是成員。

    std::string const& getSpec() { return spec; } 
    

    雖然我們在這,你可以參考給const通過std::string了。

    Part(std::string const& str) : spec(str) {} 
    
  • 工廠類

    class CarFactory 
    { 
    public: 
        Car *getCar(std::string const& carType) 
        { 
         if(carType == "Benz") // std::string::compare is for comparing by alphabetical order 
          return new Benz(); 
    
         if(carType == "Audi") 
          return new Audi(); 
    
         return nullptr; // invalid carType, return nullptr and check for that in main() 
         // You were returning previously constructed Car, was that desired? 
        } 
    }; 
    

你也忘記刪除myCar,看到對方的回答更良好的信息。

+1

正確。但是代碼中還有其他一些不好的東西。我看到evrywhere的公共數據成員不是一個虔誠的想法。如果給定字符串不是奔馳和奧迪,則在工廠類中將返回nullptr。 –

+2

@vizhanyolajos不僅這樣的問題 - 對象複製,創建的可能性部分隱含從std :: string,內存泄漏... –

5

首先,如果您要使用polymorphism,則需要聲明函數爲virtual

如果你不打算在基類中實現方法,你可以聲明它們爲pure virtual。這使得你的基類被稱爲「abstract」,你將不能創建該類的對象(在你的例子中最好的候選對象是Car對象)。

另外要小心。如果你想通過指向基類的指針銷燬對象,你還需要virtual destructor

所以把所有在一起,你需要:

class Car { 
public: 
    virtual ~Car() {} 
    virtual Part getEngine() = 0; 
    virtual Part getWheels() = 0; 
    virtual Part getBody() = 0; 
}; 

所以你的問題的根本原因,你說編譯器「嘿,我要實現汽車的方法」,但不這麼做。所以編譯器有望從你的main調用該方法,但在linking階段鏈接器找不到它們。

你需要考慮的另一個問題:

  1. 誰將摧毀你的「新」創建的對象。我建議不要 想一想,並使用shared(智能)指針(請參閱 std :: shared_pointer容器)。
  2. 當您從字符串中聲明Part類的構造函數時,您聲明可以從字符串中創建Part作爲Part x =「Part Name」;如果您不喜歡此行爲,請閱讀「explicit」關鍵字。
  3. 正如在大型項目的評論中所說的,您需要考慮encapsulation在類的「私人」部分隱藏對象實現的細節。
+0

嗨,很好解釋。你能告訴我示例代碼如何在我的代碼中使用智能指針。 – Kranthi

+0

只需將車*替換爲std :: shared_ptr

+0

而且當您創建對象時使用std :: shared_ptr (新奔馳) –

相關問題