ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【Effective C++】设计与声明——成员变量和成员函数

2022-07-09 16:33:35  阅读:144  来源: 互联网

标签:const 函数 Effective 成员 C++ Rational 封装 class


将成员变量声明为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函数就该避免,因为就像真实世界一样,朋友带来的麻烦旺旺多过价值。

 

标签:const,函数,Effective,成员,C++,Rational,封装,class
来源: https://www.cnblogs.com/Fish0403/p/16461000.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有