2010-01-21 591 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) 

这里编译器不具有隐式投射任何东西,因为提供的参数已经与引用期望绑定的类型匹配。

我希望我已经为你明确而详细地说明了你的正确理解是什么导致了这个问题,这确实很重要,但是,我强烈建议你不要像这样编写代码,而是要遵循其他人给出的建议。

相关问题