Can an object of a class be assigned to another of a different class?

I fully understand that a variable of one simple data type cannot be assigned to another of a different data type in an assignment statement, except when type-conversion(i.e. casting) is employed. For structured data types (like classes), I know that the assignment operator can be overloaded; but this only addresses objects of the same type.

My problem is that I have read data from an input file into an object of one class, but I want to transfer the contents into an object of a different class in an assignment statement. Can this be realized given that the two operands of the assignment operator (=), in this case, would be of two different types?
> Can an object of a class be assigned to another of a different class?

Yes. We would need to write an overloaded user-defined assignment operator.

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
struct A
{
    int i ;
    int j ;
};

struct B
{
    B() = default ;

    // construct object of type B from an object of type A
    explicit B( A a ) : v( a.i*100 + a.j ) {}

    // assign object of type A to object of type B
    B& operator= ( A a ) { v = a.i*100 + a.j ; return *this ; }

    long long v = 0 ;
};

int main()
{
    A a { 23, 78 } ;
    B b(a) ; // initialize b with a
    b = a ; // assign a to b
}
Thx JLBorges for your prompt response even though I don't fully understand some lines in your code; I wouldn't consider myself an expert C++ programmer yet! The reserved words (I'm guessing they are) default and explicit threw me off. If you can explain what these do/mean with respect to your code, I'd appreciate it.

More importantly, however, the two operands I want to use in the assignment statement are objects of two different derived classes from a common base class. I already have the assignment operator overloaded for that base class. How would this new info change your code segment?

If no user-defined constructors are declared for a class, the implementation would generate an implicitly declared default constructor (inline and public) if possible. For instance:
1
2
3
4
struct A
{
    long long v = 0 ;
};

Class A has an implicitly declared default constructor (which would initialize the member v with zero).

If one or more user-defined constructors are present, no such implicitly declared default constructor is generated. For instance:
1
2
3
4
5
struct B
{
    B( long long x ) { v = x ; } 
    long long v = 0 ;
};

Class B has no default constructor.

We can force the generation of the implicitly declared constructor with the keyword default For instance:
1
2
3
4
5
6
struct C
{
    C() = default ;'
    C( long long x ) { v = x ; } 
    long long v = 0 ;
}; 

Class C has an implicitly declared default constructor (which would initialize the member v with zero).

The gory details: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2326.html

Re. explicit keyword, see: http://msdn.microsoft.com/en-us/library/vstudio/h1y7x448(v=vs.110).aspx


> More importantly, however, the two operands I want to use in the assignment statement
> are objects of two different derived classes from a common base class.
> I already have the assignment operator overloaded for that base class.
> How would this new info change your code segment?

The technical answer remains the same: we would need to write overloaded user-defined assignment operators for each of them.

Could you explain the context in which this requirement arises (what precisely is the problem that you are trying to solve this way)? It is more than likely that a more elegant solution would be available.
Thx again JLBorges for your explanation and links. Let me give you a clearer
illustration of my problem. I have a base class that is basically the encapsulation of a linked list; let's call this class A. I have two different
classes derived from A, let's call them class B and class C. I have read data
from an input file into an object, say b, of class B using a user-defined, non-class function. However the data processing I want to do is on an object, say c, of class C. So, I want to copy the contents of b into c using an assignment statement; like this,

c = b;

I know there is the option of writing a new non-class function to read the input data directly into object c; but, I do not want to do that. That's the backdrop to my OP.

I have tried to overload the assignment operator in derived class C by including the function prototype

const C& operator=(const B&);

in class C's definition.

As expected, the corresponding function definition goes like this:
1
2
3
4
5
6
7
8
9
const C& C::operator=(const B& otherList)
{
        .
        .
  
       if (this != &otherList)               //compiler error  
               .
               .
}

I encountered the compiler error above which reads: comparison between distinct pointer types 'C*' and 'B*' lacks a cast.
This compiler error was one of the problems I ran into. I do understand why the compiler flagged the statement as erroneous. Is there a way to circumvent this?
> if (this != &otherList) //compiler error

This is he canonical check for self-assignment; it checks if an object is being assigned to itself. This is relevant only when the left hand side of the assignment could refer to the same object as the one on the right hand side.

In /*const*/ C& C::operator=(const B& otherList), this check is obviously unnecessary; they can never be the same object. You do not need this at all.


It may be a good idea to abstract away the implementation details of the lists by using the iterator pattern.
http://sourcemaking.com/design_patterns/iterator

For instance, with the C++ standard library:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <vector>
#include <list>
#include <deque>
#include <iterator>

int main()
{
    const short a[] = { 0, 1, 2, 3, 4, 5, 6 } ;

    std::vector<int> vec( std::begin(a), std::end(a) ) ; // construct vector from an array
    vec.assign( std::begin(a), std::end(a) ) ; // assign array to vector

    std::list<double> lst( vec.begin(), vec.end() ) ; // construct list from vector
    lst.assign( vec.begin(), vec.end() ) ; // assign vector to list

    std::deque<long> deq ;
    deq.assign( lst.begin(), lst.end() ) ;
}

http://www.mochima.com/tutorials/STL.html#Containers_and_Iterators


A quick and dirty alternative is to implement the iterator pattern using call backs:

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
#include <iostream>
#include <functional>
#include <vector>
#include <list>
#include <memory>

struct A
{
    virtual ~A() {}
    virtual void for_each( std::function< void(int) > fn ) const = 0 ;
    virtual A& operator=( const A& that ) = 0 ;
};

struct B : A
{
    virtual void for_each( std::function< void(int) > fn ) const override
    { for( std::size_t i=0 ; i<vec.size() ; ++i ) fn( vec[i] ) ; }

    virtual B& operator=( const A& that ) override // covariant return
    {
        if( this != std::addressof(that) )
        {
            vec.clear() ;
            that.for_each( [this] ( int v ) { this->vec.push_back(v) ; } ) ;
        }
        return *this ;
    }

    std::vector<int> vec { 0, 1, 2, 3, 4, 5 } ;
};

struct C : A
{
    virtual void for_each( std::function< void(int) > fn ) const override
    { for( long v : lst ) fn(v) ; }

    virtual C& operator=( const A& that ) override // covariant return
    {
        if( this != std::addressof(that) )
        {
            lst.clear() ;
            that.for_each( [this] ( int v ) { this->lst.push_back(v) ; } ) ;
        }
        return *this ;
    }

    std::list<long> lst ;
};

int main()
{
    B b ;
    C c ;
    c = b ;
}
Topic archived. No new replies allowed.