可以将一个对象分配给另一个具有不同类型的对象
It is possible to assign an object to another with a different type
我正在处理一个 C++ 项目,我需要做一些分配代码来将一个对象分配给另一个具有不同类型的对象,如下所示:
MyClass1 o1;
MyClass2 o2;
o2 = o1;
Ofc,我们可以借助 MyClass2
的复制赋值运算符来完成这项工作:MyClass2& operator=(const MyClass1&)
.
但这对我来说将是一项非常繁重的工作,因为已经有成千上万的 类,需要像 o2 = o1
这样的作业。我不想为他们每个人都添加一个复制赋值运算符...
我在想是否有其他方法,比如一些TMP方法来帮助我...
我可以确保 MyClass1
和 MyClass2
具有完全相同的数据成员和相同的声明顺序(见下文)。如果是这样,有没有什么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
};
顺便说一句,你可能想问为什么会有这样两个classes/structs具有相同的数据成员。嗯,这是一些历史原因,我不能把它们融合到一个class/struct。
更新
看来我的问题没有说清楚。我在这里举个例子。
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的数据成员有多少。我试图找到一些方法来避免在 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 技术...
更新2
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);
}
爱丽丝为什么要做出如此愚蠢的设计?由于某些历史原因...
为什么不使用 std::memcpy
?因为这些类包含虚函数。
是的,你可以...但我不推荐,除非这两个 类 具有完全一对一的对应关系并且在你的问题领域中具有完全相同的含义。
为什么不推荐?
- 因为操作需要手动实现(编译器无法帮助
= default
声明)。
auto operator=(MyClass1 const& other) -> MyClass2& {
std::tie(a, ch, msg) = std::tie(other.a, other.ch, other.msg);
return *this;
}
- 因为如果你定义了赋值,你最终将需要定义相等(
==
)和不等(!=
)以及两个方向。否则类将不符合逻辑。
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);
}
- 因为如果你定义赋值,你将定义一个构造函数或从一个到另一个的转换。
/*explicit?*/ operator MyClass1() const& {return {a, ch, msg};} // need thios
- 和移动构造函数?
/*explicit?*/ operator MyClass1() && {return {a, ch, std::move(msg)};} // need this
- 如果一个也可以对另一个进行排序,您将需要在两个方向上定义两者之间的顺序 类
// 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;
}
更多material:https://www.youtube.com/watch?v=ABkxMSbejZI
一旦您了解了缺点,std::tie
可以帮助您(如图所示)。
此外,如果所有 类 都是 public 且简单,则 Boost.PFR https://www.boost.org/doc/libs/1_78_0/doc/html/boost_pfr.html
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_cast
与 iClass
以及赋值进行比较。
我正在处理一个 C++ 项目,我需要做一些分配代码来将一个对象分配给另一个具有不同类型的对象,如下所示:
MyClass1 o1;
MyClass2 o2;
o2 = o1;
Ofc,我们可以借助 MyClass2
的复制赋值运算符来完成这项工作:MyClass2& operator=(const MyClass1&)
.
但这对我来说将是一项非常繁重的工作,因为已经有成千上万的 类,需要像 o2 = o1
这样的作业。我不想为他们每个人都添加一个复制赋值运算符...
我在想是否有其他方法,比如一些TMP方法来帮助我...
我可以确保 MyClass1
和 MyClass2
具有完全相同的数据成员和相同的声明顺序(见下文)。如果是这样,有没有什么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
};
顺便说一句,你可能想问为什么会有这样两个classes/structs具有相同的数据成员。嗯,这是一些历史原因,我不能把它们融合到一个class/struct。
更新
看来我的问题没有说清楚。我在这里举个例子。
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的数据成员有多少。我试图找到一些方法来避免在 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 技术...
更新2
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);
}
爱丽丝为什么要做出如此愚蠢的设计?由于某些历史原因...
为什么不使用 std::memcpy
?因为这些类包含虚函数。
是的,你可以...但我不推荐,除非这两个 类 具有完全一对一的对应关系并且在你的问题领域中具有完全相同的含义。
为什么不推荐?
- 因为操作需要手动实现(编译器无法帮助
= default
声明)。
auto operator=(MyClass1 const& other) -> MyClass2& {
std::tie(a, ch, msg) = std::tie(other.a, other.ch, other.msg);
return *this;
}
- 因为如果你定义了赋值,你最终将需要定义相等(
==
)和不等(!=
)以及两个方向。否则类将不符合逻辑。
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);
}
- 因为如果你定义赋值,你将定义一个构造函数或从一个到另一个的转换。
/*explicit?*/ operator MyClass1() const& {return {a, ch, msg};} // need thios
- 和移动构造函数?
/*explicit?*/ operator MyClass1() && {return {a, ch, std::move(msg)};} // need this
- 如果一个也可以对另一个进行排序,您将需要在两个方向上定义两者之间的顺序 类
// 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;
}
更多material:https://www.youtube.com/watch?v=ABkxMSbejZI
一旦您了解了缺点,std::tie
可以帮助您(如图所示)。
此外,如果所有 类 都是 public 且简单,则 Boost.PFR https://www.boost.org/doc/libs/1_78_0/doc/html/boost_pfr.html
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_cast
与 iClass
以及赋值进行比较。