2014-09-27 26 views
6

這是代碼:在構造函數中,候選人預計1個參數,提供0

class cat 
{ 
    private: 
     int height; 
    public: 
     cat (int inputHeight); 
}; 

cat::cat (int inputHeight) 
{ 
    height = inputHeight; 
} 

class twoCats 
{ 
    private: 
     cat firstCat; 
     cat secondCat; 
    public: 
     twoCats (cat theFirstCat); 
     void addSecondCat (cat theSecondCat); 
}; 

twoCats::twoCats (cat theFirstCat) 
{ 
    firstCat = theFirstCat; 
} 

void twoCats::addSecondCat (cat theSecondCat) 
{ 
    secondCat = theSecondCat; 
} 

int main() {return 0;} 

而且這些都是錯誤的:

main.cpp: In constructor ‘twoCats::twoCats(cat)’: 
main.cpp:24:34: error: no matching function for call to ‘cat::cat()’ 
main.cpp:24:34: note: candidates are: 
main.cpp:9:1: note: cat::cat(int) 
main.cpp:9:1: note: candidate expects 1 argument, 0 provided 
main.cpp:1:7: note: cat::cat(const cat&) 
main.cpp:1:7: note: candidate expects 1 argument, 0 provided 
main.cpp:24:34: error: no matching function for call to ‘cat::cat()’ 
main.cpp:24:34: note: candidates are: 
main.cpp:9:1: note: cat::cat(int) 
main.cpp:9:1: note: candidate expects 1 argument, 0 provided 
main.cpp:1:7: note: cat::cat(const cat&) 
main.cpp:1:7: note: candidate expects 1 argument, 0 provided 

我不明白以下幾點:

  1. 爲什麼twoCats的構造函數嘗試調用cat的默認構造函數?當然,它不需要構造一個cat的實例,因爲當twoCats被初始化時,它將被傳遞一個cat的已經初始化的實例,該實例已經通過了int height參數?
  2. 爲什麼相同的錯誤消息塊顯示兩次?我在Ubuntu 12.04上撥打了g++ main.cpp
+1

首先,你不要在你的構造函數中初始化任何東西。您分配給已經初始化的對象。其次,你只嘗試初始化'firstCat'。 'secondCat'還有什麼用? – chris 2014-09-27 16:58:16

+5

這已被答覆以前的無數次。 – juanchopanza 2014-09-27 16:58:27

+0

@juanchopanza至少你不得不承認OP在第一槍時得到了正確的問題格式;)... – 2014-09-27 17:02:57

回答

4

您需要默認構造函數或在twoCats構造函數初始化列表中初始化cat對象以避免默認構造。

爲什麼twoCats的構造函數嘗試調用cat的默認構造函數 ?當然,它不需要構建貓的實例 ,因爲當twoCats被初始化時,它將被傳遞已經初始化的貓的實例,該實例已經通過了int高度 參數?

它需要構建默認值cat對象

private: 
    cat firstCat; 
    cat secondCat; 

twoCats類,因爲你沒有初始化。在您的構造函數中

cat::cat (int inputHeight) 
{ 
    height = inputHeight; 
    ^^^^^^^^^^^^^^^^^^^^ 
} // this is assignment 

這是分配給已經創建的對象。

的規則如下:如果你不ctor初始化列表,然後

  1. 默認ctor
  2. 你最終分配給已經默認在ctor身體構造的對象明確初始化實例。

因此,如果您沒有在初始化列表中進行初始化,您將面臨額外調用的懲罰。

C++標準n3337 § 12.6.2/10初始化鹼和成員

在非委託構造,在 初始化前進順序如下:

- 第一,並且僅用於最基礎類(1.8), 的構造函數按照它們出現在 深度優先從左到右穿過 基類的有向無環圖的順序進行初始化,其中「left-to-對「是派生類base-specifier-list中 基類的出現順序。

- 然後,直接基類中聲明的順序初始化爲它們出現在基地說明符列表(不管 MEM-初始化的順序的) 。

- 然後,非靜態數據成員在他們的類定義聲明 順序初始化(再次不管 MEM-初始化的順序)。

- 最後,執行構造函數體的複合語句

[注意:聲明順序要求確保基址和 成員子對象以 初始化的相反順序銷燬。 - 注完]

Here is a code demo.

+0

這就是全部好,但我認爲它不回答問題,並且可以引入性能問題 – thang 2014-09-27 17:06:14

+0

@ Cheersandhth.-Alf True,謝謝你,chnaged – 4pie0 2014-09-27 17:14:52

+0

非常感謝你的澄清,完美的回答,這正是我想要的! – texasflood 2014-09-27 21:03:33

1

這兩個cat實例都必須在它們開始存在時進行初始化。

爲了避免這種情況,您可以將每個實例創建推遲到您需要的時候。

一個簡單而安全的方法是使用std::vector來保存實例。

class cat 
{ 
    private: 
     int height; 
    public: 
     cat (int inputHeight); 
}; 

cat::cat (int inputHeight) 
{ 
    height = inputHeight; 
} 

#include <vector> 
#include <utility> 

class twoCats 
{ 
    private: 
     std::vector<cat> cats_; 

    public: 
     twoCats (cat theFirstCat) 
     { cats_.push_back(std::move(theFirstCat)); } 

     void addSecondCat (cat theSecondCat) 
     { cats_.push_back(std::move(theSecondCat)); } 
}; 

int main() {return 0;} 

或者,你可以使用boost::optional

或動態分配實例(使用智能指針如unique_ptr來管理生命期)。

或者讓貓成爲默認構造。


正如a comment注意到「唐卡」,原來的設計並不能保證一個twoCats有兩隻貓。它可以只有一隻貓,或者三隻或更多的貓。所以這將是一個好主意更改設計

例如,有一個構造函數需要兩個cat參數或cat高度。

或者換一個例子,改名爲twoCats

+1

我認爲這很好,除了你可以無意中多次添加第二隻貓秒。在這種情況下,twoCats不是兩隻貓,這是以後的錯誤處方。 – thang 2014-09-27 17:16:08

+0

@thang:true。我保留了設計。如果開始改變設計,它就會變成......不同的東西*。 – 2014-09-27 17:17:30

+0

我想如果有一個約束,它必須是兩個貓(2貓),那麼實現要麼不應該使用向量(例如,2個顯式智能指針)或使用向量並檢查大小。在那個筆記上,addSecondCat應該可能是setSecondCat。類名和(一些)聲明要求關聯1-2。 – thang 2014-09-27 17:20:35

0

當你的類名(twoCats)指出它代表兩隻貓總是。這些小貓可能活着,死亡或甚至還沒有出生。但它應該是其中的兩個。

你的設計是錯誤在這個意義上,無論是:

  • cat應該能夠代表非出生的貓(所以它應該有 公共默認構造函數設置對象爲非出生的狀態開始)或
  • 你的twoCats構造函數應該在一開始就接受兩隻貓。
+0

好吧,設計沒有錯。它取決於要求:p可能是這樣做的意圖是有一組至多2只貓和至少1只貓。 – thang 2014-09-27 17:25:39

+0

我提出的MWE沒有很好的想出來,是的,對於這個例子,我真的應該確保構造函數只能接受兩隻貓,所以應該總是有兩個貓對象:) – texasflood 2014-09-27 21:16:05

2

我會初始化類twoCats這樣的:

class twoCats 
{ 
private: 
    cat firstCat; 
    cat secondCat; 
public: 
    twoCats (const cat& theFirstCat, const cat& theSecondCat) 
     : firstCat (theFirstCat), secondCat (theSecondCat) 
    { 
    } 

};

這裏的重要部分是冒號在構造函數:之後。它啓動成員初始化列表,如果可能的話,所有的類數據成員都應該被初始化。

初始化數據成員在C++中是一個相當複雜的問題,我建議你google它。

特別是,由於您有兩個類類型的成員,因此無論如何,編譯器都會嘗試在構造函數中初始化它們。它爲每隻貓都這樣做,這可能是您獲得錯誤消息塊兩次的原因。在默認情況下,編譯器會嘗試使用默認構造函數初始化您的cat數據成員,即沒有參數的構造函數。不幸的是,cat沒有默認的構造函數,因爲你聲明瞭一個參數。換句話說,每個貓都必須用一個參數初始化(或者複製,或者在C++ 11中移動)。

我不建議宣佈額外的構造函數cat不帶參數:它似乎有一隻貓的沒有「默認HIGHT」,並通過另一個答案建議-1很奇怪:它似乎並沒有構建有效的對象,並且在使用任何cat的成員函數之前,您必須檢查此默認值。

編輯:這是從格式的角度來看。至於你的程序的語義,複製貓可能是錯誤的。也許你確實需要一個引用(或一個指針)來初始化你的twoCats,或許不是。

+0

謝謝,這是非常有幫助的,我想想我的實際問題(這個貓程序只是一個MWE),我會用指針來解決這個問題 – texasflood 2014-09-27 21:13:24

相關問題