使用相等运算符初始化对象

initialise object with equal operator

在class定义如下命名为foo

class foo{
private:
    string str;
public:
    foo operator = (string s){
         str = s;
    }
};

int main(){
    foo a = "this initialization throwing an error";
    foo b;
    b = "but assignment after declaration is working fine";
}

error: conversion from 'const char [38]' to non-scalar type 'foo' requested

上述错误仅在我通过声明为对象实例赋值时引起,但如果我与声明分开赋值,那么重载的等于 = 运算符工作正常。

我想在任何方法中使用等于运算符将字符串分配给对象 并且 作为声明 就像 foo a = "abcd";

当你有

type name = something;

你不是在做赋值,而是你有copy-initialization(不要以为即使它被称为复制也可以移动)。这意味着您的 class 中需要一个构造函数,其参数与 =.

右侧的参数相匹配

在这种情况下,您没有采用 std::stringconst char*const char[] 的构造函数,因此编译器无法在那里构造实例。

第二种情况有效的原因是

b = "but assignment after declaration is working fine";

没有尝试构造任何东西,因此它调用了有效的赋值运算符,因为

"but assignment after declaration is working fine"

可以转换为std::string

如果您希望 class 可以从字符串文字或 cstring 构造,那么您可以以

的形式向其添加构造函数
foo(const char* str) : str(str) {}

你的问题是

foo a = "initialization string";

试图创建一个 foo 类型的对象,但是没有定义接受字符串类型参数的构造函数。

你可以这样定义一个:

foo(const std::string& s) : str(s) {}
foo(const char* s) : str(s) {}

创建对象时,代码 使用构造函数初始化 它,即使创建使用 = 符号也是如此:

struct S {
    S(int);
};

S s = 3; // initialization, not assignment

形式上,该初始化使用 S(int) 创建类型为 S 的临时对象,然后使用复制构造函数从临时对象构造对象 s

这与处理现有对象的赋值有很大不同:

S s1;
s1 = 3; // assignment

此处,如果 S 定义了赋值运算符,则赋值将使用赋值运算符。这就是原始代码中 b = 行起作用的原因。

对于初学者来说,尽管编译器不会发出诊断消息,但 class 定义中的赋值运算符

class foo{
private:
    string str;
public:
    foo operator = (string s){
         str = s;
    }
};

无效,因为它 return 什么都没有,而它具有 return 类型 foo

你应该这样写

    foo & operator = ( const std::string &s){
         str = s;
         return *this;
    }

由于您既未声明默认构造函数也未声明复制构造函数,因此编译器代替您隐式声明了它们。

所以实际上你的 class 只有两个构造函数。具有以下声明的默认构造函数

foo();

和具有以下声明的复制构造函数

for( const foo & );

在此声明中

foo a = "this initialization throwing an error";

编译器假定在右侧有一个类型为 foo 的对象,您将使用它来创建对象 a。也就是说,在此声明中,编译器尝试应用隐式创建的复制构造函数。为此,它需要将字符串文字转换为 foo 类型的对象。但是 class 没有转换构造函数,它是一个带有可以接受字符串文字的参数的构造函数。结果编译器发出错误

error: conversion from 'const char [38]' to non-scalar type 'foo' requested

const char[33]是声明右侧字符串字面量的类型。

在此代码段中

foo b;
b = "but assignment after declaration is working fine";

首先使用编译器默认构造函数隐式定义的 foo 类型的对象 b 创建,然后在第二个语句中使用显式定义的赋值运算符在 class。根据运算符的定义,它为数据成员 str 分配了一个 std::string 类型的临时对象,该对象是从使用的字符串文字构造的。有可能是因为classstd::string有对应的转换构造函数

您在第一种情况下所拥有的称为 copy initialization,如文档中所述:

The equals sign, =, in copy-initialization of a named variable is not related to the assignment operator. Assignment operator overloads have no effect on copy-initialization.

注意错误。所以可能的解决方案:

首先你可以创建一个构造函数,它接受 std::string:

foo( const std::string &s );

这将允许您通过以下方式创建 foo

foo f( "abc" );

甚至这样:

foo f = foo( "abc" );

但是你的语句仍然会失败,因为:

in addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.

因此,要使您的语句按原样工作,您需要添加此构造函数:

 foo( const char *str );

注意:当您添加适当的构造函数时,您不需要定义赋值运算符 - 将使用转换构造函数。并且您的重载赋值运算符应该 return 引用 foo.