【问题标题】:initialise object with equal operator用相等运算符初始化对象
【发布时间】:2017-03-31 04:01:21
【问题描述】:

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

【问题讨论】:

  • 你需要一个转换构造函数,即foo(const std::string& s) : str(s) {}
  • 失败的代码不是“给对象赋值...”而是试图初始化对象,这需要一个构造函数。
  • 您需要从 const char* 构建构造函数。

标签: c++ c++11 initializer


【解决方案1】:

当你有

type name = something;

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

在这种情况下,您没有采用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::stringconst char*const char[] 因为在我的情况下,我认为它接受数据作为std::string 但是直到现在我才发现它是const char*
  • @Encryptor 刚刚在答案中添加了一个构造函数,它应该可以满足您的需求。
  • “或需要转换为其中一种类型”是不正确的陈述
  • @Slava 是的。当我打字的时候,我认为这听起来不对。感谢您给我打电话。
  • @NathanOliver 现在你的最后一句话令人困惑:)
【解决方案2】:

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

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

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

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

foo( const std::string &s );

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

foo f( "abc" );

甚至这个:

foo f = foo( "abc" );

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

此外,复制初始化中的隐式转换必须 直接从初始化器产生 T ,同时,例如 直接初始化期望从 T 的构造函数参数的初始值设定项。

所以要让你的陈述按原样工作,你需要添加这个ctor:

 foo( const char *str );

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

【讨论】:

    【解决方案3】:

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

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

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

    这与赋值有很大的不同,它处理一个已经存在的对象:

    S s1;
    s1 = 3; // assignment
    

    这里,如果S 定义了一个,则赋值将使用赋值运算符。这就是原始代码中的b = 行有效的原因。

    【讨论】:

    • “在形式上,初始化使用 S(int) 来创建一个 S 类型的临时对象”这个说法有任何根据吗?
    • @Slava - 是的,这是标准中的要求。从 C++ 98 之前就一直是这样。
    • 但是效果完全不同,如果我显式创建临时的,那么它会允许转换,否则是不允许的。看我的回答。
    • @Slava - 抱歉,我不知道你在说什么。 S s = 3; 的效果,正式地,正是我所描述的。为简单起见,我遗漏的是允许编译器省略该副本并直接构造s,这就是我使用“正式”一词的原因。
    • 我的意思是S s = 3;S s = S(3);是不同语义的不同语句。
    【解决方案4】:

    你的问题是

    foo a = "initialization string";
    

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

    你可以这样定义:

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

    【讨论】:

    • 但是 OP 的代码必须创建一个匿名的临时 std::string。也许编译器会优化它?
    • 您还可以创建一个接受std::string 的移动构造函数。如果您使用字符串文字调用它,这将解决问题。
    • 很遗憾,你错了,这个ctor不会解决OP的问题
    • @Slava 你说得对,那是行不通的。我使用带有const char* 的构造函数更新了帖子。
    【解决方案5】:

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

    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] 是声明右侧的字符串字面量的类型。

    在这段代码中sn-p

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-27
      • 2011-10-30
      • 1970-01-01
      • 2013-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多