在运行时动态更改虚拟指针

时间:2011-11-06 03:11:24

标签: c++ vptr

所以假设我有两个类继承了一个具有纯虚函数的基类。这两个类都实现了自己的该函数版本,但是不添加其他成员变量,因此它们具有相同的大小。现在有时,在程序执行过程中,我想将一个类转换为另一个类而不复制其所有数据。所以基本上我想让它使用其他类的虚拟表。有可行的方法吗?

7 个答案:

答案 0 :(得分:5)

执行此操作的可移植方法是实现自己的类系统,该系统实际上具有可以复制的虚拟指针。

标准C ++中没有虚拟指针这样的东西。

答案 1 :(得分:4)

不。就语言而言,没有虚拟表这样的东西,更不用说关于它的外观/它包含的内容/存储位置的规则。

某种形式的构图可能更适合您的任务。

答案 2 :(得分:4)

挪威安德森咨询公司(现为埃森哲公司)的一位年轻同事曾向我提出过​​一个严重的问题。他们的应用程序是用Visual Basic开发的,需要花费很长时间才能加载。他怀疑这可能是因为他们将每个类放在自己的DLL中?

害怕最坏的情况,我进一步询问。是的,他们也遇到了任意崩溃等问题。

他怀疑是否可以通过替换vtable指针将其他无法解释的崩溃连接到他们在运行时更改对象类型的巧妙方案?

我建议也许他们不应该真的做这些事情。他怀疑地看着我,冒险说他们没有时间从头开始做事。事实上,他们已经在扩展它,并且存在各种问题,就像他们的项目负责人坚持他们在客户站点工作而不是参加强制性会议。对我来说,这听起来像是蘑菇管理(让它们在黑暗中,当头部弹出,切割它时):这些东西经常在一起。

无论如何,我给你同样的建议:不要。

也许你可以改为实现快速移动操作,将数据从 a 移动到 b

或者,您可能会发现这是过早优化的全部情况?

干杯&第h。,

答案 3 :(得分:3)

  

有可行的方法吗?

绝对不是。规范没有定义虚函数如何实现的细节,因此没有 portable 方式来假装一个虚拟类是另一个虚拟类。

答案 4 :(得分:3)

正如其他答案所说,实际上改变vtable肯定是不可移植的。

但是,有几种解决方法可以让您在不实际更改类类型的情况下完成类似的语义:

这个最简单的解决方案是使用描述当前实现的枚举“滚动自己的”继承:

class MyClass
{
    public:
    enum DerivedType { A, B };

    private:
    DerivedType myType;

    public:
    void myVirtualFunction()
    {
        if (myType == A)
            myAFunction();
        else
            myBFunction();
    }
}

您还可以使用函数指针作为公共成员变量,该变量设置为指示类类型的函数。然后你可以将函数指针设置为另一个类的函数来“改变它的类型”

由于你提到你想避免复制数据,你可以保留不同的类,但是有所有成员变量的引用计数指针,这样你就可以快速地创建相反类型的新对象。 / p>

答案 5 :(得分:1)

使用新的展示位置怎么办?这可能不是很容易移植,但是它确实完成了必需的事情-替换了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();

没有提及明显的事情,例如班级人数,最佳实践等。

答案 6 :(得分:0)

即使这个问题很老,我想提出一个方法来做到这一点。 (对可移植性不太确定)

根据我的理解,你有一个类BC继承自某个类A,并且它们之间只存在一个虚函数。 (如果BC不相关,我在此处提供的方法也有效。)

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

可以查看代码here

为了更进一步,我们可以创建一个功能,从一种类型转换为另一种类型,而不会给gnat的后端关于它们之间发生的事情。

template< typename TO, typename FROM >
TO& convert(FROM const& from) {
    parent* p = new child< FROM >(from);
    return as< TO >(p);
};

这可以运行here

(意识到我错过了这些示例代码链接中的继承,但在阅读了我认为实际需要的问题之后。因此,要查看没有继承的测试,请转到here

我开始玩的其他一些代码我认为也可以帮助一些...

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