Assignment operator overloading error (no viable overloaded operator)

I am learning to use assignment operators. So as part of the process, I wrote a simple program as shown below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  #include <iostream>

// class with strings & constructors
class outputname{
private:
    std::string first_name, last_name; 
public:
    outputname(){first_name = " "; last_name = " ";}
    outputname(std::string fn, std::string ln){
        setname(fn, ln);
    }
    void printname(){std::cout << "The name is " << first_name << " " << last_name << ".\n";}
    void setname(std::string fn, std::string ln){first_name = fn; last_name= ln;}
    
    // assignment overloading operator
    outputname& operator=(const outputname &src){
    first_name = src.first_name;
    last_name = src.last_name;
    return *this;
}
 
};

//overloading operators

int main(int argc, char** argv) {
    
    outputname name1("Don", "Draper");
    outputname name2;
    name2 = ("Peggy" , "Olsen");   // error = no viable overloaded operator
     
    name1.printname();
    name2.printname();
    
    return 0;
}


As can be seen in the above program, "name1" prints fine. But as part of the assignment operator function, i figured my object "name2" would work. But it doesn't. I'm guessing this is due to the fact the assigned variable is perceived as "char". I could be wrong. Can someone please point me in the right direction to fix this. Thank you.
It should be name2 = name1; OR outputname name2 = name1;
name2 = outputname("Peggy" , "Olsen");
you're trying to assign a r-value so, (a) you need to create the object first through its overloaded ctor and (b) use std::move() with the copy assignment operator (or overload the move assignment operator):
 
 name2 = (std::move(outputname("Peggy" , "Olsen")));   // std::move -> #include <utility> 

and the move assignment operator would look something like this:
1
2
3
4
5
outputname& operator=(const outputname &&src){
    first_name = std::move(src.first_name);
    last_name = std::move(src.last_name);
    return *this;
    }
Last edited on
#include <string>

and

name2 = outputname("Peggy" , "Olsen");
I apologize. I should have been a bit more specific. gunnerfunner's reply is more in tune with what I want to accomplish. I want to be able to use the overloaded assignment operator while accomplishing this task.

@gunnerfunner, while your reply works, I have a question .

Is it not possible to have the program work where I load 'name2' with just the name and have the assignment operator accordingly modified to take in just the name.

I want to be able to have the following work.

name2 = ("Peggy", "Olsen");

I believe the above can be done with necessary modifications to the assignment operator. I'm not sure how to modify the assignment operator.
AFAIK this is not possible because the assignment operator must be a non-static member function:
http://stackoverflow.com/questions/871264/what-does-operator-must-be-a-non-static-member-mean
but let's see if someone can come up with something ingenious that might help you achieve your goals

edit: btw lastchance and my solutions are essentially the same upto calling the overloaded ctor
Last edited on
Thanks gunnerfunner. The reason why I'm obsessing with this idea is because I'm studying using the book "C++ without Fear" by Brian Overland. In this he actually comes up with an option to do exactly what I want to do.

How he does it is ,

He uses the <string.h> header and uses the string class to add an assignment overloaded operator.

i'll list out how he does it,

#include <iostream>
#include <string.h>

using namespace std;

class String{
private:
char *ptr;
public:
String();
String(char *s);
String (const String &src);
~String();

String& operator=(const String &src)
{cpy(src.ptr); return *this;}

String& operator=(char *s)
{cpy(s); return *this;}
void cpy(char *s);
};

int main(){
String a;
a = "I";
system ("PAUSE");
return 0;
}

String::String(){
ptr = new char[1];
ptr[0] = '\0';
}

String::String(char *s){
int n = strlen(s);
ptr = new char[n+1];
strcpy(ptr, s);
}

String::String(const String &src){
int n = strlen(src.ptr);
ptr = new char[n+1];
strcpy(ptr, src.ptr);
}

String::~String(){
delete [] ptr;
}

void String::cpy(char *s){
delete [] ptr;
int n = strlen(s);
ptr = new char[n+1];
strcpy(ptr, s);
}

So i wanted to do was avoid the String class and String Header and come up with a new way to load the char/String directly using an assignment overloading operator and be able to do the following,

name2 = ("Peggy", "Olsen");

If I can do this, it will also go a long way to help me better understand/design assignment operators . So any help is appreciated.

p:s Even if it is a definite NO that it cannot be done, atleast I would have better understood how assignment operators function and their limitations.
Last edited on
Could do with trimming blanks off start and end, but that's for another day.

Your book is just showing you the rudiments of a new String class. The book I originally taught myself from did something similar: seems to be a standard challenge. In your example there is only one item on the RHS of the assignment, not two ... and therein lies the problem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
 #include <string>

// class with strings & constructors
class outputname{
private:
    std::string first_name, last_name; 
public:
    outputname(){first_name = " "; last_name = " ";}
    outputname(std::string fn, std::string ln){
        setname(fn, ln);
    }
    void printname(){std::cout << "The name is " << first_name << " " << last_name << ".\n";}
    void setname(std::string fn, std::string ln){first_name = fn; last_name= ln;}
    
    // assignment overloading operator
    outputname& operator=(const outputname &src){
       first_name = src.first_name;
       last_name = src.last_name;
       return *this;
    }
    outputname& operator=(const char* allname){
       std::string src( allname );
       first_name = src.substr( 0, src.find( " " ) );
       last_name = src.substr( src.find_last_of( " " ) + 1 );
       return *this;
    }
 
};

//overloading operators

int main(int argc, char** argv) {
    
    outputname name1("Don", "Draper");
    outputname name2;
//  name2 = outputname("Peggy" , "Olsen");  
    name2 = "Peggy Olsen";
     
    name1.printname();
    name2.printname();
    
    return 0;
}

Last edited on
I want to be able to have the following work.

name2 = ("Peggy", "Olsen");
Use curly braces instead:

name2 = {"Peggy", "Olsen"};
Thanks lastchance. That works.

Am i right when I say the following assignment operator is wrong and not necessary.

// assignment overloading operator
outputname& operator=(const outputname &src){
first_name = src.first_name;
last_name = src.last_name;
return *this;
}

There's nothing wrong with your assignment operator - you can have multiple overloads, as long as they have different parameters. I would keep both. Operators are essentially just functions. BTW, there's plenty of potential validation flaws in my const char * version - may be blanks at start and/or end, may be only one name etc.

TBH, @coder777's solution is probably the easiest if you require two separate arguments. For something that has already been constructed and initialised, I can't work out whether it is implicitly creating a temporary outputname object and moving/copying, or whether this syntax is genuinely moving the items straight into the data members of name2. I'd love an explanation ... !
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>

// class with strings & constructors
class outputname {

    private:
        std::string first_name ;
        std::string last_name;

    public:

        // explicitly defaulted default constructor
        // http://www.stroustrup.com/C++11FAQ.html#default
        outputname() = default ; // first_name and last_name are initialised to empty strings

        // user-defined constructor
        outputname( std::string fn, std::string ln ) {

            setname(fn, ln);
        }

        void printname() const { // should be const

            std::cout << "The name is " << first_name << " " << last_name << ".\n";
        }

        void setname( std::string fn, std::string ln ){ first_name = fn; last_name= ln; }

        // implicitly declared copy constructor, move constructor, copy assignment and move assignment

        // "Leaving it to the compiler to implement the default behavior is simpler, less error-prone,
        // and often leads to better object code" - Stroustrup: http://www.stroustrup.com/C++11FAQ.html#default

        // Also see 'Rule of zero' in http://en.cppreference.com/w/cpp/language/rule_of_three
};

int main() {

    outputname name1("Don", "Draper"); // direct initialisation
    // or alternatively: outputname name1 { "Don", "Draper" } ;
    // see: http://www.stroustrup.com/C++11FAQ.html#uniform-init

    outputname name2; // default initialisation

    // name2 = ("Peggy" , "Olsen");   // error = no viable overloaded operator

    // see: http://www.stroustrup.com/C++11FAQ.html#uniform-init
    // { "Peggy", "Oslen" } is a prvalue of type outputname (type is deduced from context)
    name2 = { "Peggy", "Oslen" } ; // move assignment
    // equivalent to name2 = outputname { "Peggy", "Oslen" } ;

    name1.printname();
    name2.printname();

    name1 = name2 ; // copy assignment
    name1.printname();

    // auto: http://www.stroustrup.com/C++11FAQ.html#auto
    const auto peggy = name2 ; // copy initialisation
    peggy.printname() ;

    // implicit return 0 ;
}

http://coliru.stacked-crooked.com/a/3173eac9e881e217
Thank-you @JLBorges. There is helpful information to digest there.
@JLBorges That was simple and nice. A good and simple alternative . Thank you.
As a follow through I have another question with an update on the program. I appreciate any help .

The code is listed below. The question I have is trying to understand this one line.

if (this != &src)

I think I do, but please correct me if I am wrong.

I've been reading about this on different forums. I have read varying opinions of, if this line is actually necessary in the first place. Assuming this is necessary,

In reference to the following code, am I right in thinking that the purpose of this line is to check if the object being assigned to is not the same as the object invoking it. So in this example,

&src = refers to "name2" and 'this' refers to "name4".

Am I right in assuming so or have I got it all wrong ?


#include <iostream>
#include <string>

// class with strings & constructors
class outputname{
private:
std::string first_name, last_name, full_name;
public:
outputname(){first_name = " "; last_name = " ";}
outputname(std::string fn, std::string ln){
setname(fn, ln);
}
void printname(){std::cout << "The name is " << first_name << " .. " << last_name << ".\n";}
void printfullname(){std::cout << "The name is " << full_name << ".\n";}
void setname(std::string fn, std::string ln){first_name = fn; last_name= ln;}

// assignment overloading operator
outputname& operator=(const outputname &src){
if (this != &src) {
// do the assignment
first_name = src.first_name;
last_name = src.last_name;
return *this;
}
}
// outputname& operator=(const char* allname){
// std::string src( allname );
// first_name = src.substr( 0, src.find( " " ) );
// last_name = src.substr( src.find_last_of( " " ) + 1 );
// return *this;
//
// }

outputname& operator=(const char* src){
full_name = src;
return *this;
}

};

//overloading operators

int main(int argc, char** argv) {

outputname name1("Don", "Draper");
outputname name2, name3, name4;
name2 = {"Peggy", "Olsen"};
name3 = ("Pete Campbell");

name1.printname();
name2.printname();
name3.printfullname();

name4 = name2;
name4.printname();

return 0;
}
> am I right in thinking that the purpose of this line is to check if the object being assigned to
> is not the same as the object invoking it on the right hand side of the assignment.

It is a check for self-assignment.
this != /*&src*/ std::addressof(src) is true only if the lhs and the rhs of the assignment are two different objects.
@JLBorges Thank you.
Topic archived. No new replies allowed.