C++:访问虚方法

3

我正在尝试使用虚函数表通过索引在类中调用函数... 假设我们有以下代码:

class Base
{
public:
    Base() {}
    virtual ~Base() {}

    virtual Base* call_func(unsigned int func_number)
    {
       // Some way to call f_n
    }
protected:
    virtual Base* f_1() const = 0;
    virtual Base* f_2() const = 0;
    virtual Base* f_3() const = 0;
};

我已经使用函数数组、if语句和case语句实现了这个功能...所以,有没有更好的方法只使用指针来调用方法(例如访问虚表)或类似的东西?
抱歉我的英语很糟糕 :S...提前感谢!
编辑: 感谢所有建议!我将扩展我的问题:
解决这个问题后,我将创建派生类(例如derived1和derived2),它们具有不同的f_1、f_2、f_3实现,并拥有一个类控制器如下:
class Control
{
protected:
    Base* current;

public:
    Control(Base* curr = new derived1): current(curr) {}
    virtual ~Control() 
    {
        delete current;
    }
    virtual void do_something(unsigned int func_numb)
    {
        delete current
        Base* new = current->next_state(stl);
        current = new;
    }
};

2
你想要将 'call_func' 声明为虚函数吗? - Chubsdad
好问题。我同意,感觉应该有一种方法可以直接使用func_number索引到我们已知的指针表中(在所有常见的实现中都是如此)。可惜,我认为没有这种方法。因为你需要虚拟调用,所以只能使用ifswitch - Nicholas Wilson
@NicholasWilson:问题在于它只存在于“所有常见实现”中,而不是所有可能的实现中。语言规范并不要求它存在,因此没有可移植的方法来访问它。 - Mike Seymour
据我所知,针对不同编译器的虚函数表差异巨大!因此,你最好了解你的目标平台。 - Kolky
4个回答

1

可以使用 switch 语句:

switch (func_number)
{
    case 1:
        f_1();
        break;
    case 2:
        f_2();
        break;
    case 3:
        f_3();
        break;
}

或者使用函数指针数组。


抱歉,当我说 case 语句时,我想说的是 switch 语句。 - gvo
1
@gvo:啊,我在你的问题中漏掉了那个。不管怎样,那可能是最好的方法。这里有一点味道;也许如果你给我们一个更高层次的解释你想要做什么,我们可以给你一些更好的想法。 - Fred Larson

1

我猜你只是想找到解决它的所有可能方法。

您可以使用指向成员函数的映射(或向量),并在构造函数或静态地初始化它们。这可以模拟虚表。

大致如下:

class Base
{
public:
    Base() {
        functions.insert(std::make_pair(1,&Base::f_1));
        functions.insert(std::make_pair(2,&Base::f_2));
        functions.insert(std::make_pair(3,&Base::f_3));
        }
    virtual ~Base() {}
    virtual Base* call_func(unsigned int func_number)
    {
    return (this->*functions[func_number])();
}
protected:
    std::map<unsigned int, Base*(Base:: *)()const> functions;
virtual Base* f_1() const = 0;
virtual Base* f_2() const = 0;
virtual Base* f_3() const = 0;

};

这应该适用于继承类(虽然我会使call_func非虚拟)。 是的,您应该检查项目是否真的在映射(或向量)中,以及它是否不是nullptr


1

没有一种便携式的方法可以访问虚函数表;语言规范没有指定虚派发应该如何实现,因此甚至不存在要求该表存在,更不用说对程序可访问了。

没有比你提到的方法更好的方式来完成你想要的事情:一个函数指针表或者一个if/switch条件。


好的,谢谢。我觉得维基百科的关于使用伪C++的虚方法表的文章让我感到困惑。 - gvo

0

注意1:使用方法映射或switch-case方法访问方法比使用虚函数表指针更安全。

注意2:小型汇编部分适用于VC++,其他编译器不确定。

虽然有一种方式可以访问虚拟表函数:

// create our object
X *obj = new X();

// access the vtable pointer
int* vptr = *(int**)obj;

// set the this pointer
__asm
{
  mov ecx, obj
}

// call the first method from the vtable
( (void (*)()) vptr[0] )();

在此处查看深入解释: http://kaisar-haque.blogspot.nl/2008/07/c-accessing-virtual-table.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接