条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低
2013-03-24 23:56
211 查看
使一个成员为private或protected的原因是想限制对它的访问,对吗?劳累的编译器要费九牛二虎之力来确保你设置的访问限制不被破坏,对不对?所以,写个函数来让用户随意地访问受限的成员没多大意义,对不对?如果你确实认为有意义,那么请反复阅读本段,直到你不这样认为为止。
实际编程中很容易违反这条规则,下面是个例子:
class address { ... }; // 某人居住在此
class person {
public:
address& personaddress() { return address; }
...
private:
address address;
...
};
成员函数personaddress为调用者提供的是person对象中所包含的address对象,但是,也许是出于效率上的考虑,返回结果采用的是引用,而不是值(见条款22)。遗憾的是,这个成员函数的做法有违当初将person::address声明为private的初衷:
person scott(...); // 为简化省略了参数
address& addr = // 假设addr为全局变量
scott.personaddress();
现在,全局对象addr成为了scott.address的另一个名字,利用它可以随意读写scott.address。实际上,scott.address不再为private,而是public,访问级提升的根源在于成员函数personaddress。当然,本例中给出的address 的访问级是private,如果是protected,情况完全一样。
不仅仅是引用,指针也会产生以上问题。下面的例子和上面相同,只不过这次用的是指针:
class person {
public:
address * personaddress() { return &address; }
...
private:
address address;
...
};
address *addrptr =
scott.personaddress(); // 问题和上面一样
而且,对于指针来说,要担心的不仅仅是数据成员,还要考虑到成员函数。因为返回一个成员函数的指针也是有可能的:
class person; // 提前声明
// ppmf = "pointer to person member function"
// (指向person成员函数的指针)
typedef void (person::*ppmf)();
class person {
public:
static ppmf verificationfunction()
{ return &person::verifyaddress; }
...
private:
address address;
void verifyaddress();
};
如果你过去没试过象上面那样将成员函数指针和typedef结合起来的用法,可能会觉得person::verificationfunction的声明有点吓人。别害怕,它的全部含义只不过是:
· verificationfunction是一个没有输入参数的成员函数
· 它的返回值是person类中一个成员函数的指针
· 被指向的函数(即,verificationfunction的返回值)没有输入参数且没有返回值,即void。
至于static关键字,当它用于对成员的声明时,其含义是:整个类只有这个成员的一份拷贝,并且这个成员可以不通过类的具体对象来访问。有关static的完整介绍可以参考c++教程。(如果你的c++教程里没有介绍静态成员,请把书页撕了扔到垃圾回收站吧。注意封面一定不要乱扔以免破坏环境。最后,去借或买本更好的教程吧。)
最后一个例子中,verifyaddress是一个私有成员函数,这意味着它只是类的一个实现细节,只有类的成员才应该知道它(当然,友员也知道)。但是,由于公有成员函数verificationfunction返回了指向verifyaddress的指针,用户就可以做这样的事:
ppmf pmf = scott.verificationfunction();
(scott.*pmf)(); // 等同于调用
// scott.verifyaddress
这里,pmf成了person::verifyaddress的同义词,只是有个重要的区别:可以没有限制地使用它。
虽然前面说了那么多,有一天你可能为了程序的性能还是不得不写象上面那样的函数--------返回值是某个访问级较低的成员的指针或引用。但同时,你又不想牺牲private和protected为你提供的访问限制。这种情况下,你可以通过返回指向const对象的指针或引用来达到两全其美的效果。详细介绍参见条款21。
实际编程中很容易违反这条规则,下面是个例子:
class address { ... }; // 某人居住在此
class person {
public:
address& personaddress() { return address; }
...
private:
address address;
...
};
成员函数personaddress为调用者提供的是person对象中所包含的address对象,但是,也许是出于效率上的考虑,返回结果采用的是引用,而不是值(见条款22)。遗憾的是,这个成员函数的做法有违当初将person::address声明为private的初衷:
person scott(...); // 为简化省略了参数
address& addr = // 假设addr为全局变量
scott.personaddress();
现在,全局对象addr成为了scott.address的另一个名字,利用它可以随意读写scott.address。实际上,scott.address不再为private,而是public,访问级提升的根源在于成员函数personaddress。当然,本例中给出的address 的访问级是private,如果是protected,情况完全一样。
不仅仅是引用,指针也会产生以上问题。下面的例子和上面相同,只不过这次用的是指针:
class person {
public:
address * personaddress() { return &address; }
...
private:
address address;
...
};
address *addrptr =
scott.personaddress(); // 问题和上面一样
而且,对于指针来说,要担心的不仅仅是数据成员,还要考虑到成员函数。因为返回一个成员函数的指针也是有可能的:
class person; // 提前声明
// ppmf = "pointer to person member function"
// (指向person成员函数的指针)
typedef void (person::*ppmf)();
class person {
public:
static ppmf verificationfunction()
{ return &person::verifyaddress; }
...
private:
address address;
void verifyaddress();
};
如果你过去没试过象上面那样将成员函数指针和typedef结合起来的用法,可能会觉得person::verificationfunction的声明有点吓人。别害怕,它的全部含义只不过是:
· verificationfunction是一个没有输入参数的成员函数
· 它的返回值是person类中一个成员函数的指针
· 被指向的函数(即,verificationfunction的返回值)没有输入参数且没有返回值,即void。
至于static关键字,当它用于对成员的声明时,其含义是:整个类只有这个成员的一份拷贝,并且这个成员可以不通过类的具体对象来访问。有关static的完整介绍可以参考c++教程。(如果你的c++教程里没有介绍静态成员,请把书页撕了扔到垃圾回收站吧。注意封面一定不要乱扔以免破坏环境。最后,去借或买本更好的教程吧。)
最后一个例子中,verifyaddress是一个私有成员函数,这意味着它只是类的一个实现细节,只有类的成员才应该知道它(当然,友员也知道)。但是,由于公有成员函数verificationfunction返回了指向verifyaddress的指针,用户就可以做这样的事:
ppmf pmf = scott.verificationfunction();
(scott.*pmf)(); // 等同于调用
// scott.verifyaddress
这里,pmf成了person::verifyaddress的同义词,只是有个重要的区别:可以没有限制地使用它。
虽然前面说了那么多,有一天你可能为了程序的性能还是不得不写象上面那样的函数--------返回值是某个访问级较低的成员的指针或引用。但同时,你又不想牺牲private和protected为你提供的访问限制。这种情况下,你可以通过返回指向const对象的指针或引用来达到两全其美的效果。详细介绍参见条款21。
相关文章推荐
- [Effective C++]条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低
- effective C++笔记之条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低。
- 条款 30: 避免这样的成员函数:其返回值是指向成员的非 const 指针或引用, 但成员的访问级比这个函数要低
- 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低
- Effective C++ 第二版 29)内部句柄 30)成员函数返回非const指针或引用
- Java中堆内存和栈内存_在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)。修改栈指针就可以把栈中的内容销毁.这样最快
- C++ 成员函数返回引用,三种获取返回值的效果
- JavaSE8基础 函数返回抽象类的引用,这个引用指向的是子类的对象
- YTU-OJ-Problem J: B3 指向基类的指针访问派生类的成员函数
- 静态成员函数中不允许引用类的非静态成员,但可以访问对象中的非静态成员
- 指向对象的指针访问成员函数
- OJ——指向基类的指针访问派生类的成员函数
- 返回值为引用或指针的成员函数加const要注意
- 类中的this指针 一个类的指针指向NULL去访问该类的成员函数
- 关于指向空的对象指针可以访问类的不包含成员变量的成员函数的原因
- C++const对象 常量数据 常量成员函数 const指针 const引用
- 用对象和用指向基类的指针访问成员函数
- Effective C++:条款28:避免返回 handles 指向对象内部成员
- 关于 类成员函数返回指向const临时变量的引用
- effective c++条款21,22,23(返回对象时,别妄想反回其引用,将成员变量声明为private,宁可拿非成员非友元函数替换成员函数(增强封装性))