const 注意事项(初始化, 重载, 参数和返回值)

1 const 类成员初始化

(a) 成员只有 const, 类似引用, 需要在初始列表进行初始化(特殊情况C+11特性, 如果是整数(char, short, int), 可以直接在声明处赋值)。

(b) 成员既有 const 又有 static, 按照 static 初始化方式。

#include <iostream>
#include <stdio.h>
using namespace std;
 
class MyTest
{
public:
   
   MyTest():
         m_ConstString("My Test !!!")
   {
      
      
   }
   
   void printMyTest()
   {
      
      std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
      std::cout << "m_ConstString=" << m_ConstString << endl;
      std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
   }
   
 
private:
      const int m_ConstVarInt = 100;        // 成员只有 const, 特殊情况C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
      const std::string m_ConstString;      // 成员只有 const
      static const int mStaticConstVarInt;  //成员既有 const 又有 static
};
 
const int MyTest::mStaticConstVarInt = 1000;
 
 
int main()
{
   MyTest test;
   
   test.printMyTest();
   
   return 0;
}

程序运行结果:

m_ConstVarInt=100
m_ConstString=My Test !!!
mStaticConstVarInt=1000

2. const 重载

类中函数只有 const 属性不同, 可以进行函数重载(注意, 普通函数不可以)

#include <iostream>
#include <stdio.h>
using namespace std;
 
class MyTest
{
public:
   
   MyTest():
         m_ConstString("My Test !!!")
   {
      
      
   }
   
   void printMyTest()
   {
      std::cout << "printMyTest !!!!!" << endl;
      std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
      std::cout << "m_ConstString=" << m_ConstString << endl;
      std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
   }
   
   void printMyTest() const
   {
      std::cout << "printMyTest const !!!!!" << endl;
      std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
      std::cout << "m_ConstString=" << m_ConstString << endl;
      std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
   }
   
 
private:
      const int m_ConstVarInt = 100;        // 成员只有 const, 特殊情况C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
      const std::string m_ConstString;      // 成员只有 const
      static const int mStaticConstVarInt;  // 成员既有 const 又有 static
};
 
const int MyTest::mStaticConstVarInt = 1000;
 
 
int main()
{
   const MyTest testConst;
   
   //访问重载的const成员
   testConst.printMyTest();
   
   MyTest test;
   
   //访问重载的非const成员
   test.printMyTest();
   
   return 0;
}

程序运行结果:

printMyTest const !!!!!
m_ConstVarInt=100
m_ConstString=My Test !!!
mStaticConstVarInt=1000
printMyTest !!!!!
m_ConstVarInt=100
m_ConstString=My Test !!!
mStaticConstVarInt=1000

3 const 类对象

const 类对像只能访问 const 成员

#include <iostream>
#include <stdio.h>
using namespace std;
 
class MyTest
{
public:
   
   MyTest():
         m_ConstString("My Test !!!")
   {
      
      
   }
   
   void printMyTest()
   {
      std::cout << "printMyTest !!!!!" << endl;
      std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
      std::cout << "m_ConstString=" << m_ConstString << endl;
      std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
   }
   
   void printMyTest() const
   {
      std::cout << "printMyTest const !!!!!" << endl;
      std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
      std::cout << "m_ConstString=" << m_ConstString << endl;
      std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
   }
   
   void printConstVarInt()
   {
      std::cout << "printConstVarInt !!!!!" << endl;
      std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
   }
   
 
private:
      const int m_ConstVarInt = 100;        // 成员只有 const, 特殊情况C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
      const std::string m_ConstString;      // 成员只有 const
      static const int mStaticConstVarInt;  // 成员既有 const 又有 static
};
 
const int MyTest::mStaticConstVarInt = 1000;
 
 
int main()
{
   
   const MyTest testConst;
   
   // 可以访问
   testConst.printMyTest();
   
   // 不可以访问, 会报错
   // testConst.printConstVarInt();
   
   
   return 0;
}
 

程序运行结果:

 
printMyTest const !!!!!
m_ConstVarInt=100
m_ConstString=My Test !!!
mStaticConstVarInt=1000

4 const 函数改变成员变量

可以使用 mutable 在const 函数的内部改变成员变量

#include <iostream>
#include <stdio.h>
using namespace std;
 
class MyTest
{
public:
   
   MyTest():
         m_ConstString("My Test !!!")
   {
      
      
   }
   
   void printMyTest()
   {
      std::cout << "printMyTest !!!!!" << endl;
      std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
      std::cout << "m_ConstString=" << m_ConstString << endl;
      std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
   }
   
   void printMyTest() const
   {
      std::cout << "printMyTest const !!!!!" << endl;
      
      // 成员变量递增
      m_VarInt++;
      std::cout << "m_VarInt=" << m_VarInt << endl;
      
      std::cout << "m_ConstVarInt=" << m_ConstVarInt << endl;
      std::cout << "m_ConstString=" << m_ConstString << endl;
      std::cout << "mStaticConstVarInt=" << mStaticConstVarInt << endl;
   }
   
   
 
private:
      const int m_ConstVarInt = 100;        // 成员只有 const, 特殊情况C+11特性, non-static data member initializers only available with -std=c++11 or -std=gnu++11
      const std::string m_ConstString;      // 成员只有 const
      static const int mStaticConstVarInt;  // 成员既有 const 又有 static
      mutable int m_VarInt;                 // 普通成员, mutable 可以在const成员函数里面改变值
};
 
const int MyTest::mStaticConstVarInt = 1000;
 
 
int main()
{
   
   const MyTest testConst;
   
   // 第一次调用
   testConst.printMyTest();
   
   // 第二次调用
   testConst.printMyTest();
   
   
   return 0;
}
 

程序运行结果:
 

printMyTest const !!!!!
m_varInt=1
m_ConstVarInt=100
m_ConstString=My Test !!!
mStaticConstVarInt=1000
printMyTest const !!!!!
m_varInt=2
m_ConstVarInt=100
m_ConstString=My Test !!!
mStaticConstVarInt=1000

5 const 返回值

为什么有的函数的返回值为const?

对返回值使用const有可能提高一个函数的安全性和效率,否则还会出问题。

例如:

const rational operator*(const rational& lhs,
                                       const rational& rhs);

很多程序员第一眼看到它会纳闷:为什么operator*的返回结果是一个const对象?因为如果不是这样,用户就可以做下面这样的坏事:

rational a, b, c;

...

(a * b) = c;      // 对a*b的结果赋值

我不知道为什么有些程序员会想到对两个数的运算结果直接赋值,但我却知道:如果a,b和c是固定类型,这样做显然是不合法的。一个好的用户自定义类型的特征是,它会避免那种没道理的与固定类型不兼容的行为。对我来说,对两个数的运算结果赋值是非常没道理的。声明operator*的返回值为const可以防止这种情况,所以这样做才是正确的。

(a) 案例1:非const 返回值, 导致的异常操作

(testOne + testTwo) = testThree

#include <iostream>
#include <stdio.h>
using namespace std;
 
class Test
{
public:
 
   Test(const int varInt = 100):
        m_VarInt(varInt)
   {
 
   }
 
   // 返回值没有 const
   Test operator+(const Test& test)
   {
      Test tmpTest;
 
      tmpTest.m_VarInt = this->m_VarInt + test.getVarInt();
 
      return tmpTest;
   }
 
   int getVarInt()const
   {
 
      return m_VarInt;
   }
 
private:
 
   int m_VarInt;
 
};
 
 
int main()
{
  Test testOne(100);
  Test testTwo(200);
 
  Test testThree(0);
 
   //这种异常情况, 竟然可以赋值没有编译和运行报错提示
  (testOne + testTwo) = testThree;
 
  return 0;
 
}

(a) 案例2:const 返回值, 编译报错处理, 可以保证下述异常不会发生

(testOne + testTwo) = testThree

 
#include <iostream>
#include <stdio.h>
using namespace std;
 
class Test
{
public:
 
   Test(const int varInt = 100):
        m_VarInt(varInt)
   {
 
   }
 
   // 返回值加上 const
   const Test operator+(const Test& test)
   {
      Test tmpTest;
 
      tmpTest.m_VarInt = this->m_VarInt + test.getVarInt();
 
      return tmpTest;
   }
 
   int getVarInt()const
   {
 
      return m_VarInt;
   }
 
private:
 
   int m_VarInt;
 
};
 
 
int main()
{
  Test testOne(100);
  Test testTwo(200);
 
  Test testThree(0);
 
   //这种异常情况, 编译编译不能通过, 会报错处理
  (testOne + testTwo) = testThree;
 
  return 0;
 
}

 


6 const 参数

C++引用------( 临时变量、引用参数和const引用 )

如果实参与引用参数不匹配,C++将生成临时变量。如果引用参数是const,则编译器在下面两种情况下生成临时变量:

         实参类型是正确的,但不是左值

         实参类型不正确,但可以转换为正确的类型

左值参数是可被引用的数据对象,例如,变量、数组元素、结构成员、引用和被解除引用的指针都是左值,非左值包括字面常量和包含多项式的表达式。定义一个函数

double refcube(const double& ra)  
  
{  
  
         return ra*ra*ra;  
  
}  
  
   
  
double side = 3.0;  
  
double* pd = &side;  
  
double& rd = side;  
  
long edge = 5L;  
  
double lens[4]={2.3,3.4,4.5,6.7};  
  
double c1 = refcube(side);  // ra 是side  
  
double c2 = refcube(lens[2]); // ra是lens[2]  
  
double c3 = refcube(rd);   // ra 是 rd  
  
double c4 = refcube(*pd);  // ra 是*pd  
  
double c5 = refcube(edge);  // ra 是临时变量  
  
double c6 = refcube(7.0);  // ra 是临时变量  
  
double c7 = refcube(side+10.0); // ra 是临时变量

参数side lens[2] rd 和*pd都是有名称的、double类型的数据对象,因此可以为其创建引用,而不需要临时变量。但是edge虽然是变量,类型却不正确,double引用不能指向long。另一方面,参数7.0和side+10.0的类型都正确,但没有名称,在这些情况下,编译器都将生成一个临时匿名变量,并让ra指向它。这些临时变量只在函数调用期间存在,伺候编译器便可以任意将其删除

那么为什么对于常量引用,这种行为是可行的,其他情况下却不行呢?

void swapr(int& a,int& b)
 
{
 
         int temp;
 
         temp=a;
 
         a = b;
 
         b = temp;
 
}

在早期的C++较宽松的规则下,执行下面的操作将发生什么?

long a = 3,b = 5;

swapr(a,b);

这里的类型不匹配,因此编译器将创建两个临时的int变量,将他们初始化为3和5,然后交换临时变量的内容,而a和b保持不变

         简而言之,如果接受引用参数的函数的意图是修改作为参数传递的变量,则创建临时变量将阻止这种意图的实现,解决方法是,禁止创建临时变量,现在的C++标准正是这样做的、

         现在来看refcube()函数,该函数的目的只是使用传递的值,而不是修改他们,因此临时变量不会造成任何不利的影响。反而会使函数在可处理的参数种类方面更通用。因此,如果声明将引用指定为const,C++将在必要时生成临时变量、实际上,对于形参为const引用的C++函数,如果实参不匹配,则其行为类似于按值传递,为确保原始数据不被修改,将使用临时变量来存储值、

(PS:如果函数调用的参数不是左值或与相应的const引用参数的类型不匹配,则C++将创建类型正确的匿名变量,将函数调用的参数的值传递给该匿名变量,并让参数来引用该变量)

    应尽可能使用const

使用cosnt可以避免无意中修改数据的编程错误

使用const使函数能够处理const和非const实参,否则将只能接受非const数据

使用const引用使函数能够正确生成并使用临时变量

本文参考:

为什么有的函数的返回值为const?
https://blog.csdn.net/sdl111/article/details/749376

C++ const引用、临时变量 引用参数

http://blog.csdn.net/yusiguyuan/article/details/43526039

猜你喜欢

转载自blog.csdn.net/u011857683/article/details/81335128
今日推荐