在底层,一个类的 C++ 方法就像一个 C 函数,它的第一个参数是类的实例 - 或结构。
例如:
void Foo::Do();
将等效于 C 中的此声明:
void Do(Foo* this);
因此,在方法中使用成员 m_someMember 就像在 C 函数中使用 this->m_someMember。
经过这么多年的 C/C++ 编程经验,我最近才问自己:如果我从一个为 NULL 的实例指针调用一个方法怎么办?
我的猜测是:如果该方法根本没有引用任何成员,它什么时候会崩溃?
所以我做了一个快速测试(在 Windows 平台上,使用 Visual C++ 2008):
class Foo
{
public:
Foo() {}
virtual ~Foo() {}
void Do();
};
void Foo::Do()
{
cout << "Calling 'Do' for " << this << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
Foo foo;
foo.Do();
Foo* pNullFoo = 0;
pNullFoo->Do();
return 0;
}
这给出了如下输出:
Calling 'Do' for 0038FE5C
Calling 'Do' for 00000000
在对为空的实例指针进行崩溃的事后调试时,这可能会很麻烦。你可能认为如果这个方法无效就不能调用这个方法。
另一方面,如果方法被声明为虚拟的:
virtual void Foo::Do() { ... }
然后是一行:
pNullFoo->Do();
会产生缺页异常。为什么?因为具有虚拟方法的类的实例具有指向它们所属的子类虚拟方法的 vtable 的指针。所以编译器要做的第一件事就是让 pNullFoo 访问它的 vtable 成员,然后砰!
总之,这是一个更好的设计,让像 Do 这样的非上下文函数被实现为过程例程而不是方法,除非它们是虚拟的。