可以将一个对象分配给另一个不同类型的对象

发布于 2025-01-15 09:44:41 字数 2562 浏览 2 评论 0原文

我正在处理一个 C++ 项目,我需要执行一些赋值代码将一个对象分配给另一个具有不同类型的对象,如下所示:

MyClass1 o1;
MyClass2 o2;
o2 = o1;

Ofc,我们可以在 MyClass2< 的复制赋值运算符的帮助下完成这项工作/code>: MyClass2&运算符=(const MyClass1&)

但这对我来说将是一项非常繁重的工作,因为有数千个类需要执行像o2 = o1这样的作业。我不想为它们逐一添加复制赋值运算符...

我在想是否有其他方法,例如一些 TMP 方法来帮助我...

我可以确保 MyClass1MyClass2 具有完全相同的数据成员和相同的声明顺序(见下文)。如果是这样,是否有一些 TMP 方法可以帮助我?

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
};

顺便说一句,您可能想问为什么有这样两个类/结构具有相同的数据成员。好吧,这是一些历史原因,我无法将它们融合到一个类/结构中。

更新

看来我没有把我的问题说清楚。我在这里举个例子。

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);
}

这是真实的案例。如您所见,o1.? = o2.? 包含多行,这取决于 MyClass1/MyClass2.= o2.? 有多少个数据成员。我正在尝试找到某种方法来避免在 func2 中对所有数据成员进行一一的愚蠢分配。

另外,正如我所说,我有数千个类,例如 MyClass1/MyClass2,这意味着这些类具有完全不同的数据成员。

那么对于 MyClass1 和 MyClass2,o1.? = o2.?o1.a = o2.a; o1.ch = o2.ch; o1.msg = o2.msg; 但对于其他类,可能会变成o1.f = o2.f; o1.vec = o2.vec;。这就是为什么我想我可能需要一些 TMP 技术...

UPDATE2

Alice 开发了类:

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

我正在开发函数:

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);
}

为什么 Alice 做了这么愚蠢的设计?由于某些历史原因...

为什么不使用 std::memcpy ?因为这些类都包含虚函数。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦幻的味道 2025-01-22 09:44:41

是的,你可以......但我不推荐,除非这两个类具有精确的一一对应关系,并且在您的问题领域具有完全相同的含义。

为什么不推荐?

  1. 因为该操作需要手动实现(编译器无法帮助使用=default声明)。
    auto operator=(MyClass1 const& other) -> MyClass2& {
        std::tie(a, ch, msg) = std::tie(other.a, other.ch, other.msg);
        return *this;
    }
  1. 因为如果定义了赋值,您最终需要定义相等 (==) 和不等 (!=),并且是双向的。否则,类的行为将不符合逻辑。
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. 因为如果定义赋值,您将定义一个构造函数或从一个构造函数到另一个构造函数的转换。
    /*explicit?*/ operator MyClass1() const& {return {a, ch, msg};} // need thios
  1. 和移动构造函数?
    /*explicit?*/ operator MyClass1() && {return {a, ch, std::move(msg)};} // need this
  1. 如果一个也可以订购另一个,那么您将需要在两个方向上定义两个类之间的顺序,
// won't even try
// bool operator<
// bool operator<=
// bool operator>
// bool operator>=
// bool operator<
// bool operator<=
// bool operator>
// bool operator>=

就此而言,与一个类一起使用的任何函数都应该与另一个类一起使用,因为好吧,当您分配时,您是在说在其他事物中,有两件事在逻辑上是相等的。

完整代码在这里: https://godbolt.org/z/c8d34eT48

虽然这似乎是你的情况(尽管这是一个非常可疑的案例),正如您所看到的,您通过定义两个类之间的相等性打开了潘多拉魔盒。

只需调用“赋值”convert,您就可以省去很多麻烦。不要使用operator=。我推荐的代码是仅使用另一个名称:

    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;
    }

更多材料:https://www.youtube.com /watch?v=ABkxMSbejZI

一旦您了解了这些缺点,std::tie 就可以为您提供帮助(如图所示)。
另外,如果所有类都是公共且简单的,则 Boost.PFR https ://www.boost.org/doc/libs/1_78_0/doc/html/boost_pfr.html

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

眼睛会笑 2025-01-22 09:44:41
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
};

应该能够通过 reintrepret_castiClass 以及赋值进行比较。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文