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

时间:2016-11-16 19:40:26

标签: c++ c++11 initializer

在下面定义的类名为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";

5 个答案:

答案 0 :(得分:4)

当你有

type name = something;

您没有进行任务,而是进行了复制初始化(即使它被称为复制也不会有移动)。这意味着您需要在类中使用一个构造函数,该构造函数的参数与=右侧的参数匹配。

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

第二种情况的原因是

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

不是试图构造任何东西,因此它会调用赋值运算符,因为

"but assignment after declaration is working fine"

可以转换为std::string

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

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

答案 1 :(得分:2)

第一种情况下的内容称为copy initialization,如文档中所述:

  

在命名变量的复制初始化中,等号=,不是   与赋值运算符有关。赋值运算符重载有   对复制初始化没有影响。

预测错误。所以可能的解决方案:

首先,您可以创建一个接受std::string

的构造函数
foo( const std::string &s );

这将允许您创建foo

foo f( "abc" );

甚至是这样:

foo f = foo( "abc" );

但是你的陈述仍然会失败,因为:

  

此外,复制初始化中的隐式转换必须   直接从初始化器产生T,而例如,   直接初始化期望从中进行隐式转换   初始化器为T&#39的构造函数的参数。

所以要使你的陈述正常工作,你需要添加这个ctor:

 foo( const char *str );

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

答案 2 :(得分:1)

你的问题是那个

foo a = "initialization string";

尝试创建foo类型的对象,但是没有定义构造函数接受string类型的参数。

你可以这样定义一个:

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

答案 3 :(得分:1)

创建对象时,代码使用构造函数初始化,即使创建使用.equals符号:

=

正式地,初始化使用struct S { S(int); }; S s = 3; // initialization, not assignment 创建类型为S(int)的临时对象,然后使用复制构造函数从临时对象构造对象S

与处理现有对象的作业有很大不同:

s

此处,如果S s1; s1 = 3; // assignment 定义了赋值运算符,则赋值将使用赋值运算符。这就是原始代码中S行有效的原因。

答案 4 :(得分:1)

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

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

无效,因为它返回类型为foo时没有返回任何内容。

你应该像

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

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

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

foo();

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

for( const foo & );

在本声明中

foo a = "this initialization throwing an error";

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

  

错误:从'const char [38]'转换为非标量类型'foo'   请求的

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

在此代码段中

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

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