C 中实现“面向对象”的常见做法是使用函数指针数组。这似乎类似于 C++ vtable,本质上 C++ 虚函数机制只是围绕函数指针数组的语法糖。
但是 C 机制有一个 C++ 中缺少的附加特性。函数指针可以为 NULL,调用者可以检查函数是否为 NULL 以查看对象是否实现了某个方法。然而,在 C++ 中,方法不能为 NULL,并且类不能“不实现”方法。
在 C++ 中模仿这种行为的最接近的方法是什么?
C 中实现“面向对象”的常见做法是使用函数指针数组。这似乎类似于 C++ vtable,本质上 C++ 虚函数机制只是围绕函数指针数组的语法糖。
但是 C 机制有一个 C++ 中缺少的附加特性。函数指针可以为 NULL,调用者可以检查函数是否为 NULL 以查看对象是否实现了某个方法。然而,在 C++ 中,方法不能为 NULL,并且类不能“不实现”方法。
在 C++ 中模仿这种行为的最接近的方法是什么?
这种做法有时被称为胖接口,被认为是一种反模式。
正确的面向对象的方式是提供几个子类的层次结构,即将“可选”方法分离到一个额外的接口中,并且只让一些类实现该接口。
您可以通过测试一个类是否是相关接口的实例来测试它是否实现了这些方法。
(顺便说一句,在 C 中也是如此——虽然我从未在严肃的项目中使用过 C,但我怀疑你应该NULL
在那里使用函数指针,而不是对适当的类型层次结构建模。)
我不认为这是对 C++ 的有效使用。在 C++ 中,您应该对接口进行编程。该方法存在或不存在。您似乎将 C++ 视为简单的带有类的 C。有点多了。
界面要么说有方法,要么说没有。这提供了 C 不会提供的编译时安全性。
有一个在基类中抛出异常(让我们称之为not_implemented
)的基本虚函数。
无论如何,您通常不想这样做。如其他评论中所述,您最好有一个适当的类层次结构。
最接近的方法是设计一个类层次结构来准确建模 C 风格的 vtable 实现的内容。
两个具有不同数量元素的函数指针 (vtables) 数组正在对两个单独的类进行建模。这是很明显的,但也应该清楚的是,即使数组的大小相同,具有不同数量非空元素的 vtable 也可以对单独的类进行建模。
例如,假设我们有一个 vtable 和两个像这样聚合它的对象:
VTABLE OBJECT A OBJECT B
STRUCTURE
+-------------+ +-------------+ +-------------+
| pfnCreate | | 0x..... | | 0x..... |
+-------------+ +-------------+ +-------------+
| pfnUpdate | | 0x..... | | NULL |
+-------------+ +-------------+ +-------------+
| pfnDelete | | 0x..... | | 0x..... |
+-------------+ +-------------+ +-------------+
这两个对象不属于同一个类(至少使用类的 C++ 定义),因此您不能仅使用一个类对事态进行建模也就不足为奇了。翻译成 C++,这看起来像
class Something {
public:
void Create();
void Delete();
};
class UpdatableSomething : public Something {
public:
void Update();
}
其中 B 是 aSomething
并且 A 是 a UpdatableSomething
。
听起来您正在尝试在运行时进行兼容性检查。有几种方法可以构建类层次结构,您可以使用胖接口,其中基类实现所有可能的派生函数,如果派生类不覆盖实现,则让它们在执行时抛出错误。这就是你在 C 中所做的事情。
另一种更理想的方法是通过能力类和使用多重继承来混合能力。
查看第 9-11 页,了解有关设计和实施的更多详细信息。
http://www.umich.edu/~eecs381/lecture/IdiomsDesPattsStructural.pdf