比较结构
C++ 的方式
尽管 C++ 用简单、便捷的方式定义了结构之间的赋值:
struct A x, y;
...
x = y;
但这不适用于结构之间的比较。因此,如果要比较两个结构实例之间的等价性的话:
#include <string.h>
struct A x, y;
inline bool operator==(const A& x, const A& y)
{
return (memcmp(&x, &y, sizeof(struct A)) == 0);
}
...
if (x == y)
...
注意对于每个需要比较的结构来说,都要进行运算符重载,并且对运算符的重载会抛弃所有的语言提供的型别检查。C++ 的方式还有另一个问题,它不会检查 (x == y) 真正会发生什么,你不得不察看每一个被重载的 operator==() 以确定它们都做了些什么。
如果在 operator==() 中使用 memcmp() 还回造成潜在而丑陋的 bug 。由于对齐的缘故,结构的内存分布不一定是连续的,其中可能会有“洞”。C++ 并不保证这些用于对齐的洞中的值是确定的,所以两个结构实例可能拥有完全相同的结构成员,但是却因为洞中含有不同的垃圾而不相等。
为了解决这个问题,operator==() 可以实现为按成员(memberwise)比较。不幸的是,这是不可靠的,因为 (1) 如果一个成员被加入到结构定义中,程序员可能会忘记同时把它加到 operator==() 中,(2) 对于浮点数的 nan 值来说,就算它们按位比较相等,比较的结果也是不等。
在 C++ 中没有健壮的解决方案。
D 的方式
D 的方式明显而直接:
A x, y;
...
if (x == y)
...
创造新的 typedef 型别
C++ 的方式
Typedef 在 C++ 中是弱的,就是说,它们不会真正引入一个新的型别。编译器并不区分 typedef 和它底层的型别。
#define HANDLE_INIT ((Handle)(-1))
typedef void *Handle;
void foo(void *);
void bar(Handle);
Handle h = HANDLE_INIT;
foo(h); // 未被捕获的编码错误
bar(h); // ok
C++ 的解决方案是创建一个傀儡(dummy)结构,这个结构的唯一的目的就是获得真正的新型别所具有的型别检查和重载能力。
#define HANDLE_INIT ((void *)(-1)) struct Handle { void *ptr; Handle() { ptr = HANDLE_INIT; } // default initializer Handle(int i) { ptr = (void *)i; } operator void*() { return ptr; } // conversion to underlying type }; void bar(Handle); Handle h; bar(h); h = func(); if (h != HANDLE_INIT) ... |
D 的方式
不需要上面那种惯用的构造。只需要这样写:
typedef void *Handle = cast(void *)-1;
void bar(Handle);
Handle h;
bar(h);
h = func();
if (h != Handle.init)
...
注意,可以给 typedef 提供一个默认的初始值作为新型别的初始值。
友元
C++ 的方式
有时两个类关系很紧密,它们之间不是继承关系,但是它们需要互相访问对方的私有成员。在 C++ 中这样用到 friend 声明:
class A { private: int a; public: int foo(B *j); friend class B; friend int abc(A *); }; class B { private: int b; public: int bar(A *j); friend class A; }; int A::foo(B *j) { return j->b; } int B::bar(A *j) { return j->a; } int abc(A *p) { return p->a; } |
D 的方式
在 D 中,位于同一个模块的类隐式地具有友元访问权限。这样做是有道理的,因为关系紧密地类应该位于同一个模块中,所以隐式地赋予位于同一个模块中的其他类友元访问权限是优雅的:
module X; class A { private: static int a; public: int foo(B j) { return j.b; } } class B { private: static int b; public: int bar(A j) { return j.a; } } int abc(A p) { return p.a; } |
private 特征禁止从其他模块中访问成员。