c++ - C++ 中的虚函数困境

标签 c++

我有两个问题要问...

一个)

Class A{
int a;
public:
virtual void f(){}
};

Class B {
int b;
public:
virtual void f1(){}
};

Class C: public A, public B {

int c;
public:
virtual void f(){} // Virtual is optional here
virtual void f1(){} // Virtual is optional here

virtual void f2(){}

};

Class D: public C {
int d;
public:
void f2(){}

};

现在 C++ 说 C 的实例中不会有 3 个虚拟指针,而只有 2 个。然后,调用怎么可能说,

C* c = new D();

c->f2();//由于f2()中定义的虚函数没有对应的虚指针。后期绑定(bind)是如何完成的?..

我看到说,这个函数的虚指针是加在C的第一个父类(super class)的虚指针中的。为什么会这样?..为什么没有虚表?...

大小(*c);//应该是 24 而不是 28.. 为什么?...

另外说,考虑到上面的代码,我这样做,

void (C::*a)() = &C::f;
void (C::*b)() = &C::f1;

printf("%u", a); 
printf("%u",b);

// Both the above printf() statements print the same address. Why is that so ?...
// Now consider this,

C* c1 = new C();

c1->(*a)();

c1->(*b)();

//尽管 a 和 b 的地址相同,但调用的函数不同。这里函数的定义是如何界定的?...

希望我能尽快得到回复。

最佳答案

C++ 标准没有提及虚拟表,因此编译器可以自由选择任何方式对其进行优化。在这种情况下,它似乎已经合并了 C的 vtable 与其中一个父表,但这当然不是必需的。 需要的是,如果您这样做:

C* c = new D();
c->f2();

它调用 D::f2因为它在 C 中是虚拟的.

成员函数指针不允许转换为 void*更不用说unsigned因此,它们可能不会以预期的方式在 printf 中打印也就不足为奇了。 (它只是读取原始字节以打印出来)。原因是 %u你在对 printf 撒谎,告诉它在你实际传递的参数完全不是 int 时打印一个 int .换句话说,ab成员函数指针实际上是不同的 printf似乎在告诉你。由于它们确实不同,因此它们可以正常工作也就不足为奇了。

如果你想尝试打印编译器给你的真正的函数指针,“最可移植”的方法是 memcpy它变成一个 vector unsigned char然后打印出来。冗长的例子:

#include <iostream>
#include <vector>

class Foo
{
public:
    virtual void f1() { }
    virtual void f2() { }
    void f3() { }
};

int main()
{
    void (Foo::*a)() = &Foo::f1;
    void (Foo::*b)() = &Foo::f2;
    void (Foo::*c)() = &Foo::f3;

    std::cout << a <<std::endl;
    std::cout << sizeof(a) << std::endl;

    std::cout << b <<std::endl;
    std::cout << sizeof(b) << std::endl;

    std::cout << c <<std::endl;
    std::cout << sizeof(c) << std::endl;

    std::vector<unsigned char> a_vec(sizeof(a));
    memcpy(&a_vec[0], &a, sizeof(a));
    for(size_t i = 0; i < sizeof(a); ++i)
    {
        std::cout << std::hex << static_cast<unsigned>(a_vec[i]) << " ";
    }
    std::cout << std::endl;

    std::vector<unsigned char> b_vec(sizeof(b));
    memcpy(&b_vec[0], &b, sizeof(b));
    for(size_t i = 0; i < sizeof(b); ++i)
    {
        std::cout << std::hex << static_cast<unsigned>(b_vec[i]) << " ";
    }
    std::cout << std::endl;

    std::vector<unsigned char> c_vec(sizeof(c));
    memcpy(&c_vec[0], &c, sizeof(c));
    for(size_t i = 0; i < sizeof(c); ++i)
    {
        std::cout << std::hex << static_cast<unsigned>(c_vec[i]) << " ";
    }
    std::cout << std::endl;

    return 0;
}

在 g++ 4.2 上产生:

1
8
1
8
1
8
1 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0
c6 1d 5 8 0 0 0 0

而且你可以在这里清楚地看到所有三个成员函数指针都是不同的。

关于c++ - C++ 中的虚函数困境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7650167/

相关文章:

java - 如何使用 JavaCpp 将函数调用从 C++ 映射到 Java?

c++ - C++ 构造 "placement new"的用途是什么?

c++ - 从封闭的模板类推导返回类型时函数解析失败

c++ - 读写同一个文件c++

c++更好地初始化 map 的 map

c++ - 互斥保护宏

c++ - 在由谓词确定的 std::string 中替换字符的最 STL-ish 方法是什么?

c++ - 将字符串文字分配给 char*

c++ - 默认函数参数值在模板中可见但不应该 (gcc)

c++ - 与指向继承方法的模板化函数指针一起使用的模板化方法的问题