简体   繁体   English

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

[英]initialise object with equal operator

In the class defined as below named foo 在下面定义的类名为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

The above error is caused only when I am assigning value to the object instance with declaration but if I am assigning separately from declaration then the overloaded equal = operator is working fine. 只有当我使用声明为对象实例赋值时,才会导致上述错误,但如果我与声明分开分配,那么重载的equal =运算符正常工作。

I want in any method to assign an string to the object with equal operator and as a declaration like foo a = "abcd"; 我想在任何方法中使用相等的运算符将字符串赋值给对象作为 foo a = "abcd"; 的声明 foo a = "abcd";

When you have 当你有

type name = something;

You are not doing assignment but instead you have copy-initialization (do not that there can be a move even though it is called copy). 你没有做任务,而是你有复制初始化 (即使它被称为复制,也不要有移动)。 This means that you need a constructor in your class whose parameter matches that of the thing on the right hand side of the = . 这意味着你的类中需要一个构造函数,其参数与=右边的东西相匹配。

In this case you do not have a constructor that takes a std::string , const char* or const char[] so the compiler is unable to construct an instance there. 在这种情况下,您没有构造函数接受std::stringconst char*const char[]因此编译器无法在那里构造实例。

The reason the second case works is that 第二种情况起作用的原因是

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

Is not trying to construct anything and therefore it calls the assignment operator which does work because 不是试图构造任何东西,因此它调用赋值运算符,因为它有效

"but assignment after declaration is working fine"

can be converted to a std::string . 可以转换为std::string

If you want your class to be constructable from a string literal or cstring then you can add a constructor to it in the form of 如果您希望您的类可以从字符串文字或cstring构造,那么您可以以形式为其添加构造函数

foo(const char* str) : str(str) {}

What you have in the first case is called copy initialization and as stated in documentation: 您在第一种情况下所拥有的内容称为复制初始化 ,如文档中所述:

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. 赋值运算符重载对复制初始化没有影响。

Hense the error. 怀疑错误。 So possible solutions: 可能的解决方案:

First you can create a constructor, that accepts std::string : 首先,您可以创建一个接受std::string的构造函数:

foo( const std::string &s );

that will allow you to create foo by this: 这将允许你通过这个创建foo

foo f( "abc" );

or even this: 甚至这个:

foo f = foo( "abc" );

but your statement will still fail, because of: 但是你的陈述仍然会失败,因为:

in addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, eg direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor. 此外,复制初始化中的隐式转换必须直接从初始化器生成T,而例如,直接初始化需要从初始化器到T的构造函数的参数的隐式转换。

so to make your statement work as it is you need to add this ctor: 所以要使你的声明工作,你需要添加这个ctor:

 foo( const char *str );

Note: when you add proper ctor you do not need to define assignment operator - conversion constructor will be used. 注意:当您添加适当的ctor时,您不需要定义赋值运算符 - 将使用转换构造函数。 And your overloaded assignment operator should return reference to foo . 并且重载的赋值运算符应该返回对foo引用。

Your problem is that 你的问题是

foo a = "initialization string";

attempts to create an object of type foo however there is no constructor defined that accepts a parameter of type string. 尝试创建foo类型的对象,但是没有定义构造函数接受string类型的参数。

You could define one like this: 你可以这样定义一个:

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

When you create an object, the code initializes it with a constructor, even when the creation uses an = sign: 创建对象时,代码使用构造函数初始化它,即使创建使用了=符号:

struct S {
    S(int);
};

S s = 3; // initialization, not assignment

Formally, that initialization uses S(int) to create a temporary object of type S , and then uses the copy constructor to construct the object s from the temporary object. 在形式上,在初始化使用S(int)来创建类型的临时对象S ,然后使用拷贝构造来构造对象s从临时对象。

That's vastly different from assignment, which deals with an already existing object: 这与处理已经存在的对象的赋值有很大的不同:

S s1;
s1 = 3; // assignment

Here, the assignment would use the assignment operator if S defined one. 这里,如果S定义了赋值运算符,则赋值将使用赋值运算符。 That's why the b = line in the original code works. 这就是为什么原始代码中的b =行有效。

For starters though the compiler does not issue a diagnostic message nevertheless the assignment operator in the class definition 对于初学者来说,虽然编译器不会在类定义中发出一个诊断消息,但仍然是赋值运算符

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

is invalid because it returns nothing while it has return type foo . 是无效的,因为它返回类型为foo时不返回任何内容。

You should it write like 你应该这样写

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

As you declared neither the default constructor nor the copy constructor then the compiler implicitly declared them instead of you. 由于您既未声明默认构造函数也未声明复制构造函数,因此编译器会隐式声明它们而不是您。

So in fact your class has only two constructor. 所以实际上你的类只有两个构造函数。 The default constructor that has the following declaration 具有以下声明的默认构造函数

foo();

and the copy constructor that has the following declaration 以及具有以下声明的复制构造函数

for( const foo & );

In this statement 在这个声明中

foo a = "this initialization throwing an error";

the compiler assumes that in the right side there is an object of type foo and you are going to use it to create the object a . 编译器假定在右侧有一个类型为foo的对象,并且您将使用它来创建对象a That is in this declaration the compiler tries to apply the implicitly created copy constructor. 在此声明中,编译器尝试应用隐式创建的复制构造函数。 To so so it need to convert the string literal to an object of type foo . 所以它需要将字符串文字转换为foo类型的对象。 However the class does not have a conversion constructor that is a constructor with a parameter that can accept the string literal. 但是,该类没有转换构造函数,它是一个构造函数,其参数可以接受字符串文字。 As result the compiler issues the error 结果编译器发出错误

error: conversion from 'const char [38]' to non-scalar type 'foo' requested 错误:从'const char [38]'转换为请求的非标量类型'foo'

const char[33] is the type of the string literal in the right side of the declaration. const char[33]是声明右侧的字符串文字的类型。

In this code snippet 在此代码段中

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

at first there is created the object b of the type foo using the implicitly defined by the compiler default constructor and then in the second statement there is used the assignment operator that is explicitly defined in the class. 首先,使用由编译器默认构造函数隐式定义的foo类型创建对象b ,然后在第二个语句中使用在类中显式定义的赋值运算符。 As it follows from the definition of the operator it assigns data member str with a temporary object of type std::string that is constructed from the used string literal. 从运算符的定义开始,它为数据成员str分配一个std::string类型的临时对象,该对象是从使用过的字符串文字构造的。 It is possible because the class std::string has a corresponding conversion constructor. 这是可能的,因为类std::string具有相应的转换构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM