virtual table 如何处理纯虚函数
How does a virtual table handle pure virtual functions
编译器是如何实现纯虚函数的? class 的虚函数表是如何实现纯虚函数的?为什么我们总是需要重写纯虚函数?当我们覆盖纯虚函数时,派生的 class 的 vtable 会发生什么?
C++ 标准没有指定虚拟方法的实现。
通常它被实现为类似于函数指针数组的东西,纯虚函数通常是指向一些抛出错误的特殊函数的指针。
您必须覆盖纯虚函数,否则当某些东西试图调用这些函数时会发生什么?如果您不想覆盖某个特定函数,请不要在基础 class.
中将其设为纯虚拟
例如,您可以使用如下代码模拟虚函数:
#include <iostream>
#include <string>
#include <vector>
class A
{
public:
A() : vtable(2)
{
vtable[0] = &A::aimpl;
// B is pure virtual
vtable[1] = &A::pureVirtualFunction;
}
void a()
{
((*this).*(vtable[0]))();
}
void b()
{
((*this).*(vtable[1]))();
}
protected:
std::vector<void (A::*)()> vtable;
private:
void aimpl()
{
std::cout << "A::a\n";
}
void pureVirtualFunction()
{
throw std::runtime_error("function is pure virtual");
}
};
class B : public A
{
public:
B()
{
// Note: undefined behaviour!!! Don't do this in real code
vtable[1] = reinterpret_cast<void (A::*)()>(&B::bimpl);
}
private:
void bimpl()
{
std::cout << "B::b\n";
}
};
int main()
{
A a;
a.a();
try
{
a.b();
}
catch (std::exception& ex)
{
std::cout << ex.what() << "\n";
}
B b;
b.a();
b.b();
return 0;
}
真正的实现更为复杂,派生的 classes 能够添加到 vtable,合并来自多重继承的 vtable 等。
编译器是如何实现纯虚函数的? class 的虚函数表是如何实现纯虚函数的?为什么我们总是需要重写纯虚函数?当我们覆盖纯虚函数时,派生的 class 的 vtable 会发生什么?
C++ 标准没有指定虚拟方法的实现。
通常它被实现为类似于函数指针数组的东西,纯虚函数通常是指向一些抛出错误的特殊函数的指针。
您必须覆盖纯虚函数,否则当某些东西试图调用这些函数时会发生什么?如果您不想覆盖某个特定函数,请不要在基础 class.
中将其设为纯虚拟例如,您可以使用如下代码模拟虚函数:
#include <iostream>
#include <string>
#include <vector>
class A
{
public:
A() : vtable(2)
{
vtable[0] = &A::aimpl;
// B is pure virtual
vtable[1] = &A::pureVirtualFunction;
}
void a()
{
((*this).*(vtable[0]))();
}
void b()
{
((*this).*(vtable[1]))();
}
protected:
std::vector<void (A::*)()> vtable;
private:
void aimpl()
{
std::cout << "A::a\n";
}
void pureVirtualFunction()
{
throw std::runtime_error("function is pure virtual");
}
};
class B : public A
{
public:
B()
{
// Note: undefined behaviour!!! Don't do this in real code
vtable[1] = reinterpret_cast<void (A::*)()>(&B::bimpl);
}
private:
void bimpl()
{
std::cout << "B::b\n";
}
};
int main()
{
A a;
a.a();
try
{
a.b();
}
catch (std::exception& ex)
{
std::cout << ex.what() << "\n";
}
B b;
b.a();
b.b();
return 0;
}
真正的实现更为复杂,派生的 classes 能够添加到 vtable,合并来自多重继承的 vtable 等。