我的类没有合适的复制构造函数 - 取决于构造函数的参数是否为 const

my class has no suitable copy constructor - depending if the argument of the constructor is const or not

提问人:MIKE PAPADAKIS 提问时间:10/21/2022 最后编辑:MIKE PAPADAKIS 更新时间:10/21/2022 访问量:483

问:

问题:

我正在学习 c++,我创建了一个类来表示复数。我创建了一个复制构造函数,其格式为

complex(const complex &c);

而且程序运行良好。

然后,我删除了常量(所以它变成了:),程序不起作用。它给了我这个错误:complex( complex &c);

"message": "class \"complex\" has no suitable copy constructor"

它指的是 Add 方法。add 方法是这样的:

complex complex::add(complex &c){
    return complex( re + c.re, im + c.im);
};

如果我不添加此方法(以及通常返回在返回行中创建的复数的方法,如下所示:),则程序工作正常。当我添加这些方法时,它会给我带来错误。我不明白为什么这不起作用,因为它应该调用需要两个整数的构造函数而不是复制构造函数。return complex (integer_variable_Re, integer_variable_Im)

规格:Ubuntu的:20.04Lts

IDE:VScode

编译器:G++ 9.4

(它在某处说:,不知道它是否是编译者标准。GNU C17 (Ubuntu 9.4.0-1ubuntu1~20.04.1) version 9.4.0 (x86_64-linux-gnu) compiled by GNU C version 9.4.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP

整个错误消息: [{ "resource": "/home/papaveneti/Documents/Programming/LearnCpp/complex_classStack.cpp", "owner": "C/C++", "code": "334", "severity": 8, "message": "class \"complex\" has no suitable copy constructor", "source": "C/C++", "startLineNumber": 48, "startColumn": 12, "endLineNumber": 48, "endColumn": 19 }]

整个程序:

#include <iostream>
#include <math.h>

using namespace std;

class complex {

public:
    complex (double r, double i); // constructor
    // only method that does not specify type
    
    //default constructor
    complex (); 

    //copy cosntructor
    complex( complex &c);

    // methods: 
    complex add(complex &c);
    void norm1();

private:
    // fields:
    double re, im; 
    double norm;
};

//constructor does not need to name a type
complex::complex(double r=0.0, double i=0.0){ // default values are 0
    re = r; im = i; 
    norm1();
};

complex::complex(){
    re=im=0;
}

complex::complex( complex &c){
    re=c.re;
    im=c.im;
}

void complex::norm1(){
    norm = sqrt(re*re + im*im);
};

complex complex::add(complex &c){
    return complex( re + c.re, im + c.im);
};

int main(){
    complex c1(3,4), c2(1,2);

    return 0;
}
C++ 复制构造函数

评论

0赞 463035818_is_not_an_ai 10/21/2022
请包括完整的错误消息
1赞 user12002570 10/21/2022
显示不起作用的代码,而不是显示有效的代码。
1赞 j6t 10/21/2022
你被 C++17 之前的编译器困住了,不是吗?如果是这样,请添加相应的版本标签,否则,隐含最新的C++标准。
2赞 Jakob Stark 10/21/2022
问题不在于从两个 s 构造复杂对象,而在于返回机制中涉及的副本。double
1赞 Jakob Stark 10/21/2022
由于 C++17 返回临时对象,由于强制复制省略,不再涉及副本。因此,您的程序在 C++17 及以后可以正常编译。

答:

1赞 Jakob Stark 10/21/2022 #1

在 C++ 17 之前,以下行

return complex( re + c.re, im + c.im);

实际上包括两个对象创建。首先,使用两个参数构造一个未命名的临时对象。然后,将此对象的副本复制到存储返回值的位置。第二个副本是编译器错误的原因。复制构造函数只能用于复制临时对象,如果它是这样声明的:double

complex(const complex&);

如果省略限定符,则无法传递临时对象。const

随着 C++ 17 中强制复制省略的引入,上述行中不涉及复制(或移动)。因此,您的程序可以正常编译。您的编译器相当旧,默认情况下不使用 C++17,因此拒绝编译程序。

要解决您的问题,您可以

  • 使用采用引用的复制构造函数const
  • 添加 Move 构造函数
  • 使用 C++17(通过使用较新的编译器版本或将命令行选项传递给编译器--std=c++17

编辑:
您还应该解决@Jason Liam在此答案中提到的问题。如上所述,您的程序格式不正确,即使使用构造函数也不应编译。
const

评论

0赞 user12002570 10/21/2022
这是错误的,因为程序实际上格式不正确
0赞 user12002570 10/21/2022
即使将 添加到复制 ctor 的参数中,程序的格式仍然不正确。请参阅演示 c++14,其中 clang 拒绝程序,因为它格式不正确。const
0赞 user12002570 10/21/2022
另请参阅 clang rejects even after adding const. Program
0赞 Jakob Stark 10/21/2022
@JasonLiam 你是对的,但这并不能使我的回答无效。即使您纠正了您在答案中提到的错误,程序也无法在 C++17 之前编译(至少对于 clang 和 gcc)(请参阅此演示)
2赞 user12002570 10/21/2022
@MIKEPAPADAKIS 该程序在 C++17 中仍然无效。您使用的编译器存在错误。我正在提交错误报告。请参阅我回答的末尾。
2赞 user12002570 10/21/2022 #2

该程序在所有 C++ 版本中格式不正确gcc 和 msvc 在接受代码时是错误的,因为在类外部定义构造函数时,您为两个参数提供了默认参数,从而将其转换为默认构造函数。这是不允许的,叮当拒绝了它complex::complex(double r, double)

默认参数文档

对于非模板类的成员函数,类外定义允许使用默认参数,并与类主体内的声明提供的默认参数组合在一起。如果这些类外默认值将成员函数转换为默认构造函数或复制/移动(自 C++ 11 起)构造函数/赋值运算符,则程序格式不正确

(强调我的)

要解决这个问题,您必须确保在类外部实现 ctor 时不要添加这些默认参数,以避免将其转换为默认 ctor。此外,如果您使用的是 C++11 或 C++14,则必须向复制 ctor 的参数添加低级常量,因为在 C++17 之前没有强制复制省略。


这是 gcc 错误:

GCC 接受格式错误的类外定义程序

这是 msvc 错误:

MSVC 接受涉及构造函数内部默认参数的无效程序

评论

0赞 MIKE PAPADAKIS 10/21/2022
它的格式是否不正确,因为我(可能)有两个默认构造函数。一个会给出默认值和默认值?complex::complex(double r=0, double i=0)complex::complex()
0赞 user12002570 10/21/2022
@MIKEPAPADAKIS 是的,没错。请参阅我在回答中间引用了相同的原因:“如果这些类外默认值将成员函数转换为默认构造函数或复制/移动(自 C++11 以来)构造函数/赋值运算符,则程序格式不正确”。要解决这个问题,您必须确保在类外部实现 ctor 时不要添加这些默认参数,以避免将其转换为默认 ctor。
0赞 Jakob Stark 10/21/2022
GCC 中也有这个这个错误报告,指的是同一个问题。显然,标准的这一变化尚未在 GCC 中实施。在进行更改之前,程序的格式并不错误,但只是以这种方式产生的默认构造函数的使用是模棱两可的。
0赞 user12002570 10/21/2022
@JakobStark 所以似乎 gcc 还没有实现它,即使距离 cwg 已经很多年了!