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

initialise object with equal operator

本文关键字:初始化 对象 运算符      更新时间:2023-10-16

在下面定义的名为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";这样的声明<</strong>

div class="answers">

当你有

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) {}

在第一种情况下,您所拥有的称为复制初始化,如文档中所述:

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

纠结错误。所以可能的解决方案:

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

foo( const std::string &s );

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

foo f( "abc" );

甚至这个:

foo f = foo( "abc" );

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

此外,复制初始化中的隐式转换必须 直接从初始值设定项生成 T,而例如 直接初始化需要从 T 构造函数参数的初始值设定项。

因此,为了使您的语句按原样工作,您需要添加此 CTOR:

 foo( const char *str );

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

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

struct S {
    S(int);
};
S s = 3; // initialization, not assignment

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

这与赋值

有很大不同,赋值处理已经存在的对象:

S s1;
s1 = 3; // assignment
在这里,赋值将使用赋值运算符(

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

你的问题是

foo a = "initialization string";

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

你可以像这样定义一个:

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

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

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 的对象。但是,该类没有转换构造函数,该构造函数是具有可以接受字符串文本的参数的构造函数。结果编译器发出错误

错误:从"常量字符 [38]"转换为非标量类型"FOO" 要求

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

在此代码片段中

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

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