ICode9

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

Effective C++

2021-02-12 18:01:36  阅读:148  来源: 互联网

标签:std const 函数 Effective 成员 C++ char 类内


目录

规则2:尽量使用const、enum、inline替换#define

  1、使用const替换#define

  2、定义一个类的专属常量:在类内使用const和static

    需要在实现文件中再定义一次已经在类内声明了的static变量

  3、使用inline定义内联函数,替换#define

规则3:尽量可能使用const

  1、const用于指针中

  2、const用于STL中的迭代器中

  3、令函数返回一个const对象,往往可以避免客户因为错误使用而造成的意外,如下面的代码:

  4、const类内成员函数:在函数的参数列表后加上一个const---mutable引入

    使用const_cast为对象去掉const属性和使用static_cast为对象加上const属性的方法

规则2:尽量使用const、enum、inline替换#define

  1、使用const替换#define

1 #define ASPECT_RATIO 1.653  //大写常用语宏,但是每次出现ASPECT_RATIO的地方,预处理器都会盲目的将ASPECT_RATIO替换为1.653,导致目标代码出现多个1.653
2 const double AspectRatio = 1.653;  //此时在目标代码中只出现一个存储1.653的地方

  2、定义一个类的专属常量:在类内使用const和static

1 class GamePlayer{
2 private:
3     static const int NumTurns = 5;  //static确保了所有类对象共享NumTurns(NumTurns只有一份)、const确保了NumTurns不可以被修改
4     int scores[NumTurns];
5 };  //放在头文件中

需要在实现文件中再次定义在类中已经声明了的static变量的情况:

上面是NumTurns的声明式而非定义式。通常C++要求你给任何东西提供一个定义式,但如果它是一个类内static、const变量,只要不取它的地址,则可以声明并使用它而无需提供定义式。但是你需要取它的地址或编译器不明确的简直要看到一个定义式,那么需要提供下面的定义式:

1 class GamePlayer{
2 private:
3     static const int NumTurns;  
4     int scores[NumTurns];
5 };  //放在头文件中
6 const int GamePlayer::NumTurns = 5;  //NumTurns的定义式,放在实现文件而非头文件中,在定义式中获得初值

上述代码存在的问题:万一你的编译器错误的不允许类内static、const变量完成初值设定,而此时类内的scores需要使用该变量以确定数组内元素的个数,此时可以使用枚举:

1 class GamePlayer{
2 private:
3     enum {NumTurns = 5};    //注意此时NumTurns是一个枚举,此时对NumTurns取地址是不合法的
4     int scores[NumTurns];
5 };  //放在头文件中

 

  3、使用inline定义内联函数,替换#define

引入:

1 #define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))  //f是只带一个参数的函数
2 int a = 5, b = 0;
3 CALL_WITH_MAX(++a,b);    //在判断(++a) > (b)的时候a被累加一次,发现成立,然后再执行(++a),并将++a的结果做为f的参数。即a被累加了两次
4 CALL_WITH_MAX(++a,b+10); //在判断(++a) > (b)的时候a被累加一次,发现不成立,然后将b做为f的参数。即a被累加了一次

在调用函数f之前,a的递增此时居然取决于它被拿来和谁比较,可以使用内联函数和模板来代替:

1 template<typename T>
2 inline void callWithMax(const T & a, const T & b){
3     f(a > b ? a : b);
4 }

 

规则3:尽量可能使用const

  1、const用于指针中

1 char greeting1[] = "Hello";
2 char greeting2[] = "GoodMorning";
3 char* p = greeting1;              //non-const pointer(p可以改变指向,p=greeting2合法),non-const data(p[0]='G'合法)
4 const char* p = greeting1;        //non-const pointer(p可以改变指向,p=greeting2合法),const data(p[0]='G'不合法)
5 char* const p = greeting1;        //const pointer(p不可以改变指向,p=greeting2不合法),non-const data(p[0]='G'合法)
6 const char* const p = greeting1;  //const pointer(p不可以改变指向,p=greeting2不合法),non-const data(p[0]='G'不合法)

其中const char* p = greeting1; 也可以写成:

char const * p = greeting1;

 

  2、const用于STL中的迭代器中

1 const用于迭代器表示这个迭代器不可以指向不同的东西,但是它指向的东西是可以改变的,例如:
2 std::vector<int> vec;
3 ...
4 const std::vector<int>::iterator iter = vec.begin();  //表示iter只可以指向vec容器内的第一个元素,不可以指向其他的元素,但是iter指向的元素本身是可以被改变的
5 *iter = 10;  //合法                                   //等价于T* const (char* const)
6 ++iter;      //不合法

如果你希望迭代器所指向的东西不可以被改变,那么可以使用const_iterator:

1 std::vector<int> vec;
2 ...
3 const std::vector<int>::const_iterator iter = vec.begin();  //等价于const T* (const char*)
4 *iter = 10;  //不合法
5 ++iter;      //合法

 

  3、令函数返回一个const对象,往往可以避免客户因为错误使用而造成的意外,如下面的代码:

1 class Rational{...};
2 const Rational operator*(const Rational & lhs, const Rational & rhs);

返回一个const Rational类对象的原因是避免客户出现下面的错误:

1 int main(){
2      Rational a,b,c;
3      ...
4      (a*b)=c; 
5      (a*b)将调用operator*()函数,然后返回一个const类型的Rational类对象,然后将c赋给该const Rational类对象是不合法的!  
6 }

需要补充个的知识点:

1 const int num = 5;
2 num = 6;  //不合法!!

  4、const类内成员函数:在函数的参数列表后加上一个const

4.1两个成员函数如果只是常量性不同,则可以被重载,举例如下:

 1 class TextBlock{
 2 public:
 3     ....
 4     const char & operator[](std::size_t position) const{  //类内const成员函数
 5         return text[position];
 6     }
 7     const char & operator[](std::size_t position){             //类内non-const成员函数
 8         return text[position];
 9     }
10 private:    
11     std::string text;
12 };
13 
14 int main(){
15     TextBlock tb("Hello");
16     std::cout << tb[0];          //调用类内non-const成员函数
17     
18     const TextBlock ctb("Hello");
19     std::cout << ctb[0];         //调用类内const成员函数
20     
21     return 0;
22 }

上面的这个例子有点造作,下面的这个例子才是真实环境下的类内const成员函数使用方法:

1 void print(const TextBlock & ctb){
2     std::cout << ctb[0];        //调用类内const成员函数
3     ...
4 }

对于上面的代码,将私有变量原型的类型string改为char*,在类外使用一个指针指向了类内成员变量,那么就有可能修改该const对象中的变量,如下面的代码:

 1 class CTextBlock{
 2 public:
 3     ....
 4     const char & operator[](std::size_t position) const{  //类内const成员函数
 5         return text[position];
 6     }
 7     const char & operator[](std::size_t position){             //类内non-const成员函数
 8         return text[position];
 9     }
10 private:    
11     char* pText;
12 };
13 int main(){
14     const CTextBlock cctb("Hello");
15     char* pc = &cctb[0];
16     *pc = 'J';              //此时cctb类对象中的*pText=Jello
17     
18     return 0;
19 }

上面的程序表明,你创建了一个常量对象并设以初值,并对它只调用const成员函数,但是你最终还是改变了它的值。

写到这里,需要停下来思考一个问题:成员函数如果是const意味着什么?
bitwise constness学派认为:不可以更改对象中任何成员变量(static变量除外)才可以说是const成员函数;
logical constness学派认为:在编译器侦测不出来的情况下,可以修改对象内的某一位,使编译器侦测不来的方法是使用mutable。

不符合bitwise constness观点的代码:

 1 class CTextBlock{
 2     
 3     std::size_t length() const;
 4 private:
 5     char* pText;
 6     std::size_t textLength;   //需要在length()类内修改,但是不符合bitwise constness观点
 7     bool lengthIValid;        //需要在length()类内修改,但是不符合bitwise constness观点
 8 };
 9 std::size_t CTextBlock::length() const{
10     if(!lengthIValid){
11         textLength = std::strlen(pText);   //在const成员函数内修改了类成员,不符合bitwise constness观点
12         lengthIValid = true;               //在const成员函数内修改了类成员,不符合bitwise constness观点
13     }
14     return textLength;
15 }

由于不符合bitwise constness观点,以上代码会出现编译错误,使用mutable关键字修改类内需要在const成员函数内修改的类成员变量,修改方法如下:

 1 class CTextBlock{
 2     
 3     std::size_t length() const;
 4 private:
 5     char* pText;
 6     mutable std::size_t textLength;   //需要在length()类内修改,故将textLength声明为mutable变量
 7     mutable bool lengthIValid;        //需要在length()类内修改,故将textLength声明为mutable变量
 8 };
 9 std::size_t CTextBlock::length() const{
10     if(!lengthIValid){
11         textLength = std::strlen(pText);   //在const成员函数内修改了mutable类成员textLength,是合法的
12         lengthIValid = true;               //在const成员函数内修改了mutable类成员lengthIValid,是合法的
13     }
14     return textLength;
15 }

4.2 const和non-const成员函数避免重复

如下面的代码,存在代码重复的问题:

 1 class TextBlock{
 2 public:
 3     ....
 4     const char & operator[](std::size_t position) const{       //类内const成员函数
 5         ...                     //边界检验
 6         ...                     //数据访问
 7         ...                        //数据完整性检验
 8         return text[position];
 9     }
10     const char & operator[](std::size_t position){             //类内non-const成员函数
11         ...                     //边界检验
12         ...                     //数据访问
13         ...                        //数据完整性检验
14         return text[position];
15     }
16 private:    
17     std::string text;
18 };

于是在const operator[]()中和non-const operator[]()成员函数中,存在着代码重复的问题,解决方法是在non-const operator[]()成员函数中调用const operator[](),那么就需要为该对象加上const属性,然后调用const operator[]()函数,最后再去掉const属性。其中为对象加上const属性方法是使用static_cast,为对象去掉const属性方法是使用const_cast,修改方法如下:

 1 class TextBlock{
 2 public:
 3     ....
 4     const char & operator[](std::size_t position) const{       //类内const成员函数
 5         ...                     //边界检验
 6         ...                     //数据访问
 7         ...                        //数据完整性检验
 8         return text[position];
 9     }
10     char & operator[](std::size_t position){             //类内non-const成员函数
11         return 
12             const_cast<char &>(                    //3、将const operator[]()函数返回值的const属性去掉
13                 static<const TextBlock &>(*this)   //1、由于调用的是non-const属性的operator[](),所以*this的原型是TextBlock &,无const属性,所以static<const TextBlock &>(*this)为*this加上const属性
14                     [position]                     //2、调用const operator[]()
15             );
16     }
17 private:    
18     std::string text;
19 };

为何不可以使用const成员函数调用non-const成员函数?
const成员函数承诺不修改类内变量,但non-const成员函数没有这样的承诺,如果使用const成员函数调用non-const成员函数就有可能发生在const成员函数中修改某一个类内变量是非法的,但是跑到non-const去修改该类内变量就是合法的了。



 

标签:std,const,函数,Effective,成员,C++,char,类内
来源: https://www.cnblogs.com/YiYA-blog/p/14399047.html

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

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

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

ICode9版权所有