第一卷 第五章 5.3友元
下面的代码是《c++编程思想》里面的代码,
struct X; struct Y{ void f(X*); }; struct X{ private: int i; public: void initialize(); friend void Y::f(X*); }; void X::initialize(){ i=0; } int main(){ X x; x.initialize(); Y y; y.f(&x); }
struct X;是一个不完全类型说明,(不完整类型是这样一种类型,它缺乏足够的信息例如长度去描述一个完整的对象。)
《c++编程思想》里面的原话:struct Y有一个成员函数f(),它将修改X类型的对象。这里有一个难题,因为c++编译器要求在引用任一变量之前必须先声明,所以struct Y必须在它的的成员Y::f(X*)被声明为struct X的一个友元之前声明,但要声明Y::f(X*),又必须先声明Struct X.
解决的办法:注意到Y::f(X*)引用了一个X对象的地址,这一点很关键,因为编译器知道如何传递一个地址,这一地址具有固定的大小,而不管被传递的是什么对象,即使它还没有完全知道对象类型大小。然而,如果试图传递整个对象,编译器就必须知道X的全部定义以确定它的大小以及如何传递,这就使得程序员无法去声明一个类似于Y::g(x)的函数。
上面的斜体字是书中的原话,红色字体是我想存在疑问的地方,于是写如下代码
#include<iostream> using namespace std; struct X; struct Y{ void f(X*); void g(X); }; struct X{ private: int i; public: void initialize(); friend void Y::f(X*); friend void Y::g(X); }; void X::initialize(){ i=0; } void Y::f(X* x){ x->i=10; } void Y::g(X x){ cout<<x.i<<endl; } int main(){ X x; x.initialize(); Y y; y.f(&x); y.g(x); }
上面的代码,在Struct Y这个结构体中加入了一个成员函数,g(X),传递的参数就是struct X的整个对象,并非指针,我们也只是在Y::g(X)之前做了一个不完全类型说明,编译仍然是可以通过,并可以运行的,上面的代码和红色字体所说的相违背