2010-01-21 111 views
2

請看下面的代碼。它有什麼問題?編譯器給出了這個錯誤:C++編譯器錯誤:沒有匹配的調用函數

In copy constructor person::person(person&)': No matching function for call to person::copy(char*&, char*&)' candidates are: void person::copy(char*&, const char*&) "

下面是代碼:

class person 
{ 
    public: 
    person(); 
    person(person &); 

    private: 
    void copy(char*&,const char*&); 
    char* name, *fathername,* address; 
}; 

void person::copy(char*& n, const char*& p) 
{ 
    int result; 
    result=strcmp(n,p); 
    if(result!=0) 
    { 
    n=new char[strlen(p)+1]; 
    strcpy(n,p); 
    n[strlen(p)]='\0'; 
    } 
} 
person::person(person &object) 
{ 
    copy(name,object.name); 
    copy(fathername,object.fathername); 
    copy(address, object.address); 
} 

從這個問題的答案我的理解,直至現在由給出: 編譯器不允許將引用轉換爲常量引用,因爲引用已經是常量。他們不能指向像指針這樣的不同內存位置。我對嗎?

+0

能否請您妥善 – 2010-01-21 19:59:08

+1

即使它的工作縮進它,這個代碼泄漏內存。爲什麼不簡單地使用'std :: string'並避免這樣的錯誤? – 2010-01-21 20:04:13

+0

尊敬的先生,它不是整個代碼,我只發佈有問題的代碼。 – 2010-01-21 20:11:04

回答

4

變化

人::人(人&對象)

人::人(常量人&對象)

對於初學者...

+0

我喜歡這個提示 – 2010-01-21 19:59:41

3

編譯器告訴你這個問題 - 改變你的簽名以接受2個char *指針(而不是1個const ch ar *)並且它應該被編譯。

這個問題實際上是由於使用了引用 - 如果你創建了一個只需要2個char *指針(而不是引用)的複製方法,那麼編譯器會自動識別從char *到const char *的轉換,並且使用該方法。由於您只有一個接受對不同類型的引用的方法,它不能自動執行此操作。

+0

請用不可理解的方式解釋,我無法理解 – 2010-01-21 20:08:10

+0

這是我的問題的答案,但我需要解釋這個答案 – 2010-01-21 20:15:36

+0

請參閱下面的@Martin York的答案。記住,當你修改指針時,只能使用'&'指針(例如'char *')。 – 2010-01-21 21:05:28

10

這不是更好嗎?

class person 
{ 
private: 
    std::string name; 
    std::string fathername 
    std::string address; 
}; 

// constructor and copy constructor autogenerated! 

這是更多的「C++」這種方式;)。

+2

你好,但問題的本質是不同的 – 2010-01-21 20:09:26

+0

嘿它很好使用字符串,但從他問的問題類型來看,我認爲他更多的是在C++/oo編程中的初學者。最好是清除你的概念,比如直接跳到字符串 – 2010-01-21 20:10:09

+1

@Yogesh - 這實際上是一個原則問題 - 來自低級語言背景的人傾向於認爲std :: string是膨脹且無效的在使用中,這就是爲什麼儘管使用C++,他們使用char *。在每個這樣的情況下,有人應該指出,有std :: string ... – 2010-01-21 20:16:38

7

除非你是在不斷變化的指針計劃,你不應該通過引用指針:

變化:

void person::copy(char*& n, const char*& p) 

void person::copy(char* n, const char* p) 

這是因爲p是一個參考到特定類型。
你傳遞的對象不是確切的類型,因爲它是一個參考,他們沒有辦法將其轉換。

上面我提出的改變允許一個「指向const char」(p)的指針,從而允許通過'p'只讀訪問元素。現在一個「指向char的指針」允許對數據進行讀寫訪問,因此我們只是限制允許的行爲,因此可以將其轉換爲「指向const char」指針。

您發佈的代碼有一整套其他問題。
你想讓我們列出它們嗎?

我現在不做。我按我的時間表做。

問題:

1:您泄漏每次調用拷貝:

if(result!=0) 
{ 
    n=new char[strlen(p)+1]; // What happned to the old n? 

2:默認的賦值運算符時使用。

person a; 
person b; 
a = b; // a.name == b.name etc all point at the same memory location. 
     // Though because you do not delete anything in the destructor 
     // it is technically not an issue yet. 

3:你完成刪除析構函數中分配的成員。

{ 
    person a; 
} // A destructor called. You leak all the member here. 

4:strcpy()已經複製終止'\ 0'字符。

5:如果新的調用拋出異常。你會泄漏內存。

copy(name,object.name); 
copy(fathername,object.fathername); // If new throws in here. 
             // Then the this.name will be leaked. 

這樣做正確的用C-string是這麼難,即使是C++高手將不得不做正確這個問題。這就是爲什麼C++專家會使用std :: string而不是C-String。如果您必須使用C-Strings,那麼您應該將C-String封裝在另一個類中,以防止出現異常情況。

+0

你應該列出所有問題而不詢問 – 2010-01-21 21:17:08

+0

你的答案是有幫助的,編譯器不允許將引用轉換爲常量引用,因爲引用已經是常量,它們不能指向不同的內存位置,像指針我是對不對? ?????? – 2010-01-21 21:21:39

+1

對於「我現在不做,我按照我的日程安排」+1,歡呼我用這樣一個完整而好的方式解釋我的答案。 – gbjbaanb 2010-01-22 13:30:57

1

我感覺大方,所以這裏是一個修正版本的代碼:

class person 
{ 
public: 
    person(); 
    person(const person &); 
    ~person(); 
private: 
    void copy(char*&, // Do you understand purpose of '&' here? 
       const char*); 
    char* name; 
    char* fathername; 
    char* address; 
}; 

person::person() 
    : name(NULL), 
     fathername(NULL), 
     address(NULL) 
{ 
} 

person::~person() 
{ 
    delete[] name; 
    delete[] fathername; 
    delete[] address; 
} 

void person::copy(char*& n, // The '&' is required because the contents of `n` are changed. 
        const char* p) 
{ 
    delete[] n; 
    n = NULL;  // Here is one place where contents of `n` are changed. 
    if (p) 
    { 
     n = new char [strlen(p) + sizeof('\0')]; // Another content changing location. 
     strcpy(n, p); 
     n[strlen(p)]='\0'; 
    } 
} 

person::person(const person& object) 
{ 
    copy(name,object.name); 
    copy(fathername,object.fathername); 
    copy(address, object.address); 
} 

可以識別的缺陷或安全項目仍然潛伏?

+0

雅我知道所有這些,因爲我以前寫這不是我發佈的實際代碼,我只發佈代碼有問題,我刪除了析構函數和構造函數的代碼,因爲簡單,因爲你知道人們討厭閱讀冗長的代碼。 – 2010-01-21 21:25:50

+1

哦!哦!這不是自我安排的。 :) – Bill 2010-01-21 21:28:43

1

正如其他人所說,如果您不打算修改它,則不應通過引用傳遞char指針。

問題是,引用是非常量,因此不會綁定到臨時對象。因此傳遞的變量類型必須完全匹配。接近匹配的隱式轉換是不可接受的,因爲隱式轉換的結果是臨時的。

另一方面,const引用可以綁定到臨時對象。

void non_constant(int&); 
void constant(const int&); 

int main() 
{ 
    int i = 0; 
    unsigned u = 0; 
    non_constant(i); 
    //non_constant(u); //ERROR: not an int 
    //non_constant(10); //ERROR: literals are temporaries 
    constant(i); 
    constant(u); //OK, unsigned implicitly cast to int 
    constant(10); //OK, literals bind to const references 
} 

所以,如果你非常想保持在參數參考:

void person::copy(char*& n, const char* const& p) 
1

這是非常糟糕的設計(!)。這個代碼是buggy和非常(!)難以理解和維護。 這個問題是這個問題的延續:C++ classes , Object oriented programming

現在你正在與症狀掙扎,而不是真正的問題。而真正的問題是用C++術語不用C語言(如果你想成爲C++面向對象的程序員)。

有效C++代碼(C++,不與類C)這裏:

#include <string> 

class person 
{ 
public: 
    person(); 
private: 
    std::string name, fathername, address; 
}; 

這就是所有。所有其他事情(包括複製contstructor)C++編譯器爲您生成(與您自己的手動實現一樣有效)!這更簡單,更清晰,更容易維護和理解,首先:無bug;)。這是真正的C++代碼。

0

其他人指出你應該用指針替換引用。

這裏有一些其他的,但相關評論:

  1. 如果定義拷貝構造函數,定義賦值操作符太。在大多數情況下,他們應該一起走。

  2. 這是申報單參數的構造函數作爲explicit一個很好的做法。

  3. 命名對象作爲對象是一個壞的慣例,可能會導致混亂。很明顯,每個人類的實例都是一個對象。使用更有意義的名稱,如person(const person& other);person(const person& rhs); // after right-hand-side

  4. 使用std::string。如果您在C++編程,沒有 合理的理由不使用std::string和兼顧C字符串代替。

  5. 最後,照顧異常安全的,遵循最佳實踐,如複製在不拋出換股操作方面實現的算子的研究。由香草薩特見文章Exception-Safe Class Design, Part 1: Copy Assignment

1

其他人已經正確地回答你的問題,但似乎你不明白它爲止,所以我會盡量做到儘可能明確你。

void person::copy(char*& n, const char*& p) 

該函數要求的第二個參數的非const引用一個const指針(而不是一個常量引用像你想象的指針!)。

當你試圖調用這個函數作爲第二個參數傳遞一個指針(而不是一個const指針)時,編譯器無法爲它創建一個引用,只是因爲它期望將一個引用綁定到一個const指針,它是不允許將指針隱式轉換爲const指針,因爲非const引用可能不會綁定到右值(臨時值)。

如果你想要的功能期待一個常量引用一個const指針,你必須改變它的簽名如下圖所示:

void person::copy(char*& n, const char* const& p) 

這裏understant編譯器隱式注塑提供的指針是很重要的到結合參考,這是允許在這種情況下,由於const引用可以都綁定到右值和左值之前一個const指針。

同樣,如果你想要的功能期待const引用的指針,這可能是你的本意,那麼簽字應爲以下所示的:

void person::copy(char*& n, char* const& p) 

這裏編譯器不具有隱式投射任何東西,因爲提供的參數已經與引用期望綁定的類型匹配。

我希望我已經爲你明確而詳細地說明了你的正確理解是什麼導致了這個問題,這確實很重要,但是,我強烈建議你不要像這樣編寫代碼,而是要遵循其他人給出的建議。

相關問題