我在讨论中被问到在C ++类中添加虚函数的不足之处。我说一个缺点是类的对象有一个指向其虚拟表的指针,而对于一个小的C ++类,它在64位平台上增加了8个字节。如果创建了数百万个此类的实例,则会增加程序的内存消耗。
好的,但为什么实际上在C ++中没有像指向虚拟表的小指针或指向虚拟表的小指针或指向虚拟表的紧凑指针这样的东西。有点像这样:
class [[compact]] base {
~base(){}
virtual f() = 0;
};
class [[tiny]] another_base {
~base(){}
virtual g() = 0;
};
class [[small]] yet_another_base {
~base(){}
virtual h() = 0;
};
class child : public base {
virtual f();
};
class user_type : public another_base {
~base(){}
virtual g();
};
想象一下,我将创建许多user_type
的实例(事实上我曾经在真实程序中遇到过这种情况)。默认情况下,编译器会创建一个大小为8(在64位上)的user_type
实例。但是[[tiny]]属性只有1个字节,而[[compact]]只有4个字节。
此功能是否已经可用?如果不是,我觉得可以实现它。就像在隐藏tiny_vptr
和compact_vptr
的程序中一样,当需要找到一个指向vtable的实际指针时,只需要向它们添加第一个字节或前四个字节。因此在一个程序中,它只允许256 [[微小类]]或65000 [[小]]类。它就像是在最大速度之间选择并节省一些内存。
答案 0 :(得分:3)
没有这样的功能。
现在,C ++的vtable特性(至少你使用的部分)可以用C或C ++模拟,只需要一些语法糖。
struct my_vtable {
void(*dtor)(void*) = 0;
void(*print)(void*) = 0;
void(*add)(void*, int) = 0;
};
struct my_interface {
my_vtable const* vtable = 0;
~my_interface() { vtable->dtor(this); }
void print() { vtable->print(this); }
void add(int x) { vtable->add(this, x); }
};
等。这需要更多的工作来使构造函数和析构函数级联工作,并且虚拟继承有点粗糙,并且从多重继承构建复合vtable也是有效的(特别是如果你想要它干净)。
但你有工具。
使用此类工具,您可以实施[[tiny]]
vtable功能。
现在,如果您关心这一点,更好的方法可能是使用代理对象,您可以使用任意函数在实例中存储的任意状态查找表。您将状态存储在实例中,将表存储在其他位置。
C ++的对象系统不都是灵活的。它实现了一种安排继承和OO的方法。从布局更改到功能更改,还有许多其他有用的功能(例如,C ++不支持为类实例构建一次性vtable,或者动态创建新类型)。
将C ++继承系统视为编写OO代码的众多方法之一。知道你应该有充分的理由离开它,并尽可能地使得到的代码尽可能干净,但是不要因为你有继承关系而害怕不使用C ++继承。