Home > Software engineering >  It is possible to assign an object to another with a different type
It is possible to assign an object to another with a different type

Time:03-20

I'm working with a C project and I need to do some assignment code to assign one object to another with a different type like this:

MyClass1 o1;
MyClass2 o2;
o2 = o1;

Ofc, we can make this work with the help of a copy assignment operator of MyClass2: MyClass2& operator=(const MyClass1&).

But this gonna be a very heavy job for me because there has been thousands of classes, which need to do the assignment like o2 = o1. I don't want to add a copy assignment operator for each of them one by one...

I'm thinking if there is some other way, such as some TMP method to help me...

I can ensure that MyClass1 and MyClass2 have exactly the same data members with the same declaration order (see below). If so, is there some TMP method, which could help me?

struct MyClass1 {
    int a;
    char ch;
    std::string msg;
    // some virtual member functions
};

struct MyClass2 {
    int a;
    char ch;
    std::string msg;
    // some virtual member functions
};

BTW, you may want to ask why there are such two classes/structs with the same data members. Well, this is about some historical reason, I can't fusion them onto one class/struct.

UPDATE

It seems that I didn't make my question clear. I'll make an example here.

void doJob(const MyClass1& o1) {}
void func1(MyClass1 o1) {
    doJob(o1);
}
void func2(MyClass2 o2) {
    MyClass o1;
    o1.? = o2.?; // assign each element of o2 to o1.
    doJob(o1);
}

Here is the real case. As you see, o1.? = o2.? contains multi lines, it depends on how many data members of MyClass1/MyClass2. I'm trying to find some way to avoid this stupid assignment of all data members one by one in the func2.

Also, as I said, I have thousands of classes like MyClass1/MyClass2, meaning that these classes have totally different data members.

So for MyClass1 and MyClass2, o1.? = o2.? is o1.a = o2.a; o1.ch = o2.ch; o1.msg = o2.msg; But for other classes, it may become o1.f = o2.f; o1.vec = o2.vec;. That's why I'm thinking I may need some TMP technique...

UPDATE2

Alice developed the classes:

struct MyClass1 {// data members};
struct MyClass2 {// data members};
// MyClass1 and MyClass2 have exactly the same data members and declaration order
struct MyClass3 {// data members};
struct MyClass4 {// data members};
// MyClass3 and MyClass4 have exactly the same data members and declaration order
...
...
struct MyClass1000 {// data members};
struct MyClass1001 {// data members};
// MyClass1000 and MyClass1001 have exactly the same data members and declaration order

I'm developing the functions:

void doJob1(const MyClass1& o1) {}
void func1(MyClass1 o1) {
    doJob(o1);
}
void func2(MyClass2 o2) {
    MyClass1 o1;
    o1.? = o2.?; // assign each element of o2 to o1.
    doJob1(o1);
}
...
...
void doJob1000(const MyClass1000& o1) {}
void func1000(MyClass1000 o1) {
    doJob1000(o1);
}
void func1001(MyClass1001 o2) {
    MyClass1000 o1;
    o1.? = o2.?; // assign each element of o2 to o1.
    doJob1000(o1);
}

Why did Alice do such a stupid design? For some historical reason...

Why not using std::memcpy? Because these classes contain virtual functions.

CodePudding user response:

yes, you can... but I is not recommended unless the two classes have an exact one to one correspondence and the exact same meaning in the domain of your problem.

Why is not recommended?

  1. Because the operation needs to be manually implemented (the compiler cannot help with a = default declaration).
    auto operator=(MyClass1 const& other) -> MyClass2& {
        std::tie(a, ch, msg) = std::tie(other.a, other.ch, other.msg);
        return *this;
    }
  1. Because if you defined assignment, you will eventually need to define equality (==), and inequality (!=) and in both directions. Otherwise the clases will not behave logically.
bool operator==(MyClass1 const& mc1, MyClass2 const& mc2) {
    return std::tie(mc1.a, mc1.ch, mc1.msg) == std::tie(mc2.a, mc2.ch, mc2.msg);
}
bool operator==(MyClass2 const& mc2, MyClass1 const& mc1) {
    return std::tie(mc1.a, mc1.ch, mc1.msg) == std::tie(mc2.a, mc2.ch, mc2.msg);
}

bool operator!=(MyClass1 const& mc1, MyClass2 const& mc2) {
    return std::tie(mc1.a, mc1.ch, mc1.msg) != std::tie(mc2.a, mc2.ch, mc2.msg);
}
bool operator!=(MyClass2 const& mc2, MyClass1 const& mc1) {
    return std::tie(mc1.a, mc1.ch, mc1.msg) != std::tie(mc2.a, mc2.ch, mc2.msg);
}
  1. Because if you define assignment, you will to define a constructor or a conversion from one to the other.
    /*explicit?*/ operator MyClass1() const& {return {a, ch, msg};} // need thios
  1. and a move constructor?
    /*explicit?*/ operator MyClass1() && {return {a, ch, std::move(msg)};} // need this
  1. if one can be ordered the other also, and you will need to define order between the two classes, in both directions
// won't even try
// bool operator<
// bool operator<=
// bool operator>
// bool operator>=
// bool operator<
// bool operator<=
// bool operator>
// bool operator>=

and for that matter any function that work with one should work with the other, because well, when you assign you are saying that two things are logical equal among other tings.

full code here: https://godbolt.org/z/c8d34eT48

While it seems to be your case (albeit a very suspicious case), as you see, you open a Pandora's box by defining equality between two classes.

Just by calling the "assignment" convert instead you save your self a big headache. Don't use operator=. My recommended code is to just use another name:

    MyClass2& convert(MyClass1 const& from, MyClass2& to) {
        std::tie(to.a, to.ch, to.msg) = std::tie(from.a, from.ch, from.msg);
        return to;
    }
    MyClass2& convert(MyClass1&& from, MyClass2& to) {
        std::tie(to.a, to.ch, to.msg) = std::tie(from.a, from.ch, std::move(from.msg));
        return to;
    }

More material: https://www.youtube.com/watch?v=ABkxMSbejZI

Once you understand the drawbacks, std::tie can help you (as shown). Also, if all classes are public and simple, Boost.PFR https://www.boost.org/doc/libs/1_78_0/doc/html/boost_pfr.html

CodePudding user response:

struct iClass
{
 int a;
 char ch;
 std::string msg;
 // implement iClass == = operator
};

struct MyClass1 : virtual iClass{

// some virtual member functions
};

struct MyClass2 : virtual iClass {
// some virtual member functions
};

Should be able to compare by reintrepret_cast to iClass as well assignment.

  • Related