将成员变量声明为private

为什么成员变量不该是public?

(1)从语法一致性来说,如果成员变量不是public,就需要通过成员函数访问成员变量。public接口内的每样东西都是函数的话,客户就不需要在访问class成员时考虑要不要加小括号。(2)如果成员变量是public,任何人都可以读写它,而设为private后,可以更加精确地控制它,可以实现“不准访问”、“只读访问”以及读写访问。(3)封装,比如class中有一个成员变量mean,可以用成员函数来访问它(也就是封装了它),这样你可以替换不同的实现方式,客户最多只需重新编译。封装非常重要,你对客户隐藏成员变量(也就是封装了它们),你可以确保class的约束条件总是会获得维护,因为只有成员函数可以影响到它们。如果不隐藏,即使有class的源码,改变public事物还是会受到束缚,因为会破坏很多客户代码。public意味着不封装,不封装就意味着不可改变。protected并不比public更具封装性

宁以non-member、non-friend替换member函数

想象有一个class表示网页浏览器,其中有几个函数用来清除缓存、历史记录和cookies:

class WebBrowser {
public:
...
void clearCache();//清除缓存
void clearHistory();//清除历史记录
void removeCookies();//清除cookies
...
};

许多用户想一键清除缓存、历史记录和cookies,因此再提供一个函数:

//方法1 增加一个成员函数
class WebBrowser {
public:
...
void clearEverything();//调用clearCache、clearHistory和removeCookies
...
}; //方法2 增加一个非成员函数
void clearBrowser(WebBrowser& wb){
wb.clearCache();
wb.clearHistory();
wb.removeCookies();
}

那么哪种方法更好呢?方法2 非成员函数的方法更好。为什么呢

(1)非成员函数的封装性更高。如果一些东西被封装,它就不再可见。越多东西被封装,越少人可以看见它;越少人看见它,就有越大的弹性改变它。对于数据来说,越少的代码可以访问它,封装性就越高。当成员变量为private时,只有成员函数和友元函数可以访问它。方法1增加的成员函数clearEverything()不止可以访问class内的private函数,还可以取用private函数、enums、typedefs等等;而方法2的非成员函数,无法访问上述的东西,两者机能相当,因此选择并不增加“能够访问class内之private成分”的函数数量。

(2)方便机能扩充。在c++中,比较自然的做法是作为非成员函数并位于一个namespace中:

//头文件“webbrowser.h” 针对class WebBrowser自身
namespace WebBrowserStuff{
class WebBrowser{...}
...//核心机能,所有客户都需要的,非成员函数
}
// 头文件 “webbrowserbookmarks.h”
namespace WebBrowserStuff{
... //与书签相关的函数
}
// 头文件 “webbrowsercookies.h”
namespace WebBrowserStuff{
... //与cookies相关的函数
}

比如客户要再加影音下载相关的函数,只要写个头文件内含其声明即可

值得注意的是,因为在意封装性我们选择了非成员函数,但这并不意味着它“不可以是别的class的成员函数”,可以写一个工具类,clearBrowser()作为工具类的static member函数。

若所有参数皆需类型转换,请为此采用非成员函数

假设有一个类表示有理数:

class Rational {
public:
Rational(int numerator = 0, int denominator = 1) :n(numerator), d(denominator) {};
int numerator() const { return n; }//分子的访问函数
int denominator() const { return d; }//分母的访问函数
const Rational operator*(const Rational& rhs) const;
private:
int n, d;
};
const Rational Rational::operator*(const Rational& rhs) const
{
return Rational(this->n * rhs.n, this->d * rhs.d);
}

这样的设计可以让有理数相乘:

Rational oneEight(1, 8);
Rational oneHalf(1, 2);
Rational result = oneEight * oneHalf;

但是当你进行混合算数时:

Rational result = oneEight * 2; //可以
Rational result = 2 * oneEight; //错误

由于整数2没有相应的operator*函数所以报错。而oneEight * 2发生了隐式类型转换,将2转变为Rational。这是因为构造函数为non-explicit的,编译器才会自动转换,如果构造函数是explicit的,上两句都报错。

如果你想让他支持混合式算术运算,就让operator*成为非成员函数:

const Rational operator*(const Rational& r1, const Rational& r2)
{
return Rational(r1.numerator() * r2.numerator(), r1.denominator() * r2.denominator());
}

无论何时如果可以避免friend函数就该避免,因为就像真实世界一样,朋友带来的麻烦旺旺多过价值。

【Effective C++】设计与声明——成员变量和成员函数的更多相关文章

  1. 2.2 C++类的成员变量和成员函数

    参考:http://www.weixueyuan.net/view/6334.html 总结: 类成员的声明和定义: 类成员函数的定义分类内定义(内联)和类外定义(可用 inline 关键字 强制转换 ...

  2. 【转】C++ const成员变量和成员函数(常成员函数)

    转:http://c.biancheng.net/view/2230.html 在类中,如果你不希望某些数据被修改,可以使用const关键字加以限定.const 可以用来修饰成员变量和成员函数. co ...

  3. C++ const成员变量和成员函数(常成员函数)

    在类中,如果你不希望某些数据被修改,可以使用const关键字加以限定.const 可以用来修饰成员变量和成员函数. const成员变量 const 成员变量的用法和普通 const 变量的用法相似,只 ...

  4. java面向对象---成员变量和成员函数

    //成员变量 1.类定义了对象中所具有的变量,这些变量称作成员变量 2.每个对象都有自己的变量,和同一个类的其他对象的分开的 //函数与成员变量 1.在函数中可以直接写成员变量的名字来访问成员变量,那 ...

  5. c/c++ 类成员变量,成员函数的存储方式,以及this指针在c++中的作用

    c/c++ 类成员变量,成员函数的存储方式,以及this指针在c++中的作用 c++不会像上图那样为每一个对象的成员变量和成员函数开辟内存空间, 而是像下图那样,只为每一个对象的成员变量开辟空间.成员 ...

  6. Java的初始化执行顺序(父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数)

    1. 引言 了解Java初始化的顺序,有助于理解Java的初始化机制和内存机制. 顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量- ...

  7. 成员变量和成员函数前加static的作用?

    成员变量和成员函数前加static的作用?答:它们被称为常成员变量和常成员函数,又称为类成员变量和类成员函数.分别用来反映类的状态.比如类成员变量可以用来统计类实例的数量,类成员函数负责这种统计的动作 ...

  8. Effective C++ ——设计与声明

    条款18:让接口更容易的被使用,不易误用 接口设计主要是给应用接口的人使用的,他们可能不是接口的设计者,这样作为接口的设计者就要对接口的定义更加易懂,让使用者不宜发生误用,例如对于一个时间类: cla ...

  9. Effective C++ —— 设计与声明(四)

    条款18 : 让接口容易被正确使用,不易被误用 欲开发一个“容易被正确使用,不容易被误用”的接口,首先必须考虑客户可能做出什么样的错误操作.  1. 明智而审慎地导入新类型对预防“接口被误用”有神奇疗 ...

  10. [原]Unity3D深入浅出 - 常用类的成员变量和成员函数(Tranform、Time、Random、Mathf、Input)

    Transform的成员变量 Transform的成员函数 Time类,获取和时间相关的信息,可用来计算帧速率,调整时间流逝的速度等. Random类,可用来生成随机数,随机点和旋转. Mathf类提 ...

随机推荐

  1. linux ssh连接

    前言 整理以前的随笔. 正文 首先更新源 sudo apt-get update 安装ssh服务 sudo apt-get install openssh-server 检测是否已启动 ps -e | ...

  2. js es6 delete

    前言 首先delete 不同于nodejs delete,看下有什么不同. 正文 var test=5; delete test; console.log(test); 结果是test没有受到任何影响 ...

  3. 在windows电脑中安装redis

    1,github下载地址:https://github.com/MSOpenTech/redis/tags 2,下载完成后,解压到对应文件夹 3,打开redis.windows.conf,在#requ ...

  4. CSS之定位Position

    前言 之前在<CSS之浮动>中,我当时是想一起说说定位的,因为我在很多地方看到有把float和position放在一起讲的,说它们的一些属性值可以使元素脱离文档流,但是没想到在准备内容的时 ...

  5. 力扣209(java&python)-长度最小的子数组(中等)

    题目: 给定一个含有 n 个正整数的数组和一个正整数 target . 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, ...

  6. 对接HiveMetaStore,拥抱开源大数据

    本文分享自华为云社区<对接HiveMetaStore,拥抱开源大数据>,作者:睡觉是大事. 1. 前言 适用版本:9.1.0及以上 在大数据融合分析时代,面对海量的数据以及各种复杂的查询, ...

  7. 【ASPLOS 2022】机器学习访存密集计算编译优化框架AStitch,大幅提升任务执行效率

    简介: 近日,关于机器学习访存密集计算编译优化框架的论文<AStitch: Enabling A New Multi-Dimensional Optimization Space for Mem ...

  8. Elasticsearch生态&技术峰会 | 阿里云Elasticsearch云原生内核

    简介: 开源最大的特征就是开放性,云生态则让开源技术更具开放性与创造性,Elastic 与阿里云的合作正是开源与云生态共生共荣的典范.值此合作三周年之际,我们邀请业界资深人士相聚云端,共话云上Elas ...

  9. [FAQ] edge 等浏览器的 debug 栏的 "网络" 中看不到网络请求

      如果 edge 等浏览器的 debug 栏的 "网络" 中看不到网络请求, 出现这类情况一般是在 debug 栏的 "设置" 中进行了过滤,可能是不小心点了 ...

  10. [PHP] Laravel 获取模型/表的所有字段

      获取指定表的所有字段名: use Illuminate\Support\Facades\Schema; // 表名不带前缀 $columns = Schema::getColumnListing( ...