简体   繁体   中英

initialise object with equal operator

In the class defined as below named 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.

I want in any method to assign an string to the object with equal operator and as a declaration like 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.

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 .

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

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 :

foo( const std::string &s );

that will allow you to create foo by this:

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.

so to make your statement work as it is you need to add this ctor:

 foo( const char *str );

Note: when you add proper ctor you do not need to define assignment operator - conversion constructor will be used. And your overloaded assignment operator should return reference to 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.

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.

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. That's why the b = line in the original code works.

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 .

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 . 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 . 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[33] is the type of the string literal in the right side of the declaration.

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. 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. It is possible because the class std::string has a corresponding conversion constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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