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引用使函数能够正确生成并使用临时变量