因此,假设我有两个类继承了一个具有纯虚函数的基类。这两个类都实现了它们自己版本的该函数,但不添加额外的成员变量,因此它们具有相同的大小。现在有时,在程序执行过程中,我想将一个类转换为另一个类而不复制其所有数据。所以基本上我想让它使用其他类的虚拟表。有没有一种便携的方式来做到这一点?
7 回答
实现此目的的可移植方法是实现您自己的类系统,该类系统实际上具有可以复制的虚拟指针。
标准 C++ 中没有虚拟指针之类的东西。
没有。就语言而言,没有虚拟表之类的东西,更不用说关于它的外观/包含的内容/存储位置的规则了。
某种形式的构图可能更适合您的任务。
挪威 Andersen Consulting(现为埃森哲)的一位年轻同事曾向我提出一个严重问题。他们用 Visual Basic 开发的应用程序需要很长时间才能加载。他怀疑这可能是因为他们将每个类都放在了自己的 DLL 中?
担心最坏的情况,我进一步询问。是的,他们也有任意崩溃等问题。
他怀疑其他莫名其妙的崩溃可能与他们通过替换 vtable 指针在运行时更改对象类型的巧妙方案有关?
我建议也许他们不应该真的做这些事情。他怀疑地看着我,并冒险说他们没有时间再从头开始做事。事实上,他们已经在扩展它,并且存在各种问题,例如他们的项目负责人坚持他们在客户现场工作而不是参加强制性会议。对我来说,这听起来像蘑菇管理(让它们在黑暗中,当一个头弹出时,切掉它):这些东西经常在一起。
无论如何,我给你同样的建议:不要。
也许您可以改为实施快速移动操作以将数据从a移动到b?
或者,也许您会发现这都是过早优化的情况?
有没有一种便携的方式来做到这一点?
绝对不。规范没有定义如何实现虚函数的细节,因此没有可移植的方法来假装一个虚拟类是另一个。
正如其他答案所说,实际上更改 vtable 绝对是不可移植的。
但是,有几种变通方法可以让您在不实际更改类类型的情况下完成类似的语义:
这个最简单的解决方案是使用描述当前实现的枚举“滚动你自己的”继承:
class MyClass
{
public:
enum DerivedType { A, B };
private:
DerivedType myType;
public:
void myVirtualFunction()
{
if (myType == A)
myAFunction();
else
myBFunction();
}
}
您还可以将函数指针用作公共成员变量,将其设置为指示类类型的函数。然后你可以将函数指针设置为另一个类的函数来“改变它的类型”
由于您提到要避免复制数据,因此您可以保留不同的类,但具有指向所有成员变量的引用计数指针,以便您可以快速创建彼此相反类型的新对象。
使用新展示位置怎么样?这可能不是很便携,但它确实做了所需的事情——替换了 vtable,仅此而已。只需要照顾构造函数 - 使用一个空的。
struct Base
{
int someData;
virtual int GetValue() = 0;
};
struct A : public Base
{
int GetValue() override { return 11111; }
};
struct B : public Base
{
int GetValue() override { return 22222; }
};
A ob;
ob.someData = 123;
auto ob2 = new (&ob) B;
auto value = ob2->GetValue();
更不用说诸如班级规模、最佳实践等显而易见的事情了。
尽管这个问题很老,但我想提出一种方法来做到这一点。(不太确定便携性)
据我了解,您有一个类B
,并且C
从某个类继承,A
并且它们之间仅存在一个虚拟函数。(我在这里介绍的方法在相关B
且不C
相关的情况下也有效。)
class A {
public:
virtual std::string hello() = 0;
};
class B : public A {
public:
virtual std::string hello() { return "B"; }
};
class C : public A {
public:
virtual std::string hello() { return "C"; }
};
然后您想接听电话并B
获取.C
hello
"B"
所以,有一种方法可以创建一个淡化的版本,boost::any
只要它适合,它就会将任何东西投射到任何东西上:)
struct parent {};
template< typename T >
struct child : public parent {
child(T const& t): item(t){}
mutable T item;
};
template< typename T >
T& as(parent const & p) { return static_cast< child< T > const& >(p).item; }
然后将它们混合在一起:
B b;
parent* p = new child< B >(b);
std::cout << as< C >(*p).hello() << std::endl;
// ==== OUTPUT ====
// B
可以在此处查看实际代码。
更进一步,我们可以创建一个从一种类型转换为另一种类型的函数,而无需提供关于它们之间发生的事情的 gnat 后端。
template< typename TO, typename FROM >
TO& convert(FROM const& from) {
parent* p = new child< FROM >(from);
return as< TO >(p);
};
这可以在这里运行。
(意识到我错过了这些示例代码链接中的继承,但在阅读了这个问题后,我认为这是真正想要的。所以,要查看没有继承的测试,请转到此处)
我开始使用的其他一些代码我认为也可能对一些人有所帮助......
#include <iostream>
#include <string>
class B {
public:
virtual char hello() {return 'B';}
};
class C {
public:
virtual int hello() {return 65;}
};
struct parent {};
template< typename T >
struct child : public parent {
child(T const& t): item(t){}
mutable T item;
};
template< typename T >
T& as(parent const & p) { return static_cast< child< T > const& >(p).item; }
template< typename TO, typename FROM >
TO& convert(FROM const& from) {
parent* p = new child< FROM >(from);
return as< TO >(*p);
};
int main()
{
B b;
std::cout << convert< C, B >(b).hello() << std::endl;
C c;
std::cout << convert< B, C >(c).hello() << std::endl;
}
// ==== OUTPUT ====
// 66
// A
弄清楚如何在转换函数中完成所有操作:
template< typename TO, typename FROM >
TO& convert(FROM const& from) {
struct parent {};
struct child : public parent {
child(FROM const& t): item(t){}
mutable FROM item;
};
struct sibling : public parent {
sibling(TO const& t): item(t){}
mutable TO item;
};
parent* p = new child(from);
return static_cast< sibling const& >(*p).item;
};