const相关用法(Effective C++_3)
2015-09-04 20:01
381 查看
一、构造操作和赋值操作的区别如果一个新对象被定义,一定会有一个构造函数被调用,不可能调用赋值操作;如果没有新对象定义,就不会有构造函数调用,那么就只能调用赋值操作;
class Demo; Demo w1;//调用默认构造函数 Demo w2(w1);//调用复制构造函数 w1=w2;//调用赋值操作 Demo w3=w2//调用复制构造函数二、尽量使用const,enums代替宏(Effective C++_2)三、const的用法(Effective C++_3)1、常变量
const float PI=3.14159; //定义了常变量PI const int Number_of_Student=100; //定义了常变量Number_of_Student常变量必须只能在说明时进行初始化;常变量初始化之后,不允许再被赋值;常变量必须先说明后使用。2、引用使用const(1)const引用是指向const对象的引用。
const int i = 10; const int &ref = i;可以读取ref,但不能修改。这样做是有意义的,因为i本身就不可修改,当然也不能通过ref来修改了。所以也就有将const变量赋值给非const引用是非法的。
int &ref1 = i; // error: nonconst reference to a const object(2)非const引用是指向非const类型变量的引用。const引用可以初始化为不同类型的对象或者右值(如字面值常量),但非const引用不可以。
// legal for const references only int i = 10; const int & ref = 42; const int & ref1 = r + i; double d = 3.14; const int &ref2 = d; //注意这里的类型不同以绑定到不同类型的ref2为例解释原因,编译器会把ref2相关的代码转换如下:
int temp = d; const int &ref2 = temp; // bind ref2 to temporaryref2实际上是绑定到一个临时变量上,如果ref2不为const,那么按道理就可以通过修改ref2而修改d的值,但实际上d并不会改变。所以为了避免这个问题,ref2只能是const。非const引用只能绑定到与该引用同类型的对象,const引用则可以绑定到不同但相关的类型的对象或绑定到右值。2、指针使用constconst出现在*的左边,表示所指之物是常量,出现在右边,表示指针本身是常量,如果出现在两边,表示所指之物和指针本身均是常量
const char* p="greeting";//所指物是常量,不可改变 char* const p="greeting";//指针本身是常量 const char* const p="greeting"//所指物和指针本身均是常量注意:
const char* p="greeting";与下面的等价 char const* p="greeting"3、迭代器使用const假如你希望迭代器所指之物不可改变,你需要使用const_iterator:
vector<int> vec; ...... vector<int>::const_iterator iter=vec.begin(); *iter=10;//错误,*iter是个常量 iter++;//可以如果你希望迭代器本身不改变,你需要使用const,声明迭代器为const就像声明指针为const一样(T* const),表示这个迭代器不得指向其他东西,但是其所指之物可以发生改变
vector<int> vec; ...... const vector<int>::iterator iter=vec.begin(); *iter=10;//可以 iter++;//错误,iter是个const4、函数声明,包括函数返回值、参数使用const(1)函数参数使用const,可以保证传入的值,在函数内部操作时,不改变原有的值(2)函数的返回值为const可以防止不适当的操作,比如
class Ration{}; const Ration operator*(const Ration& lhs,const Ration& rhs); ...... Ration a,b,c; ....... if(a*b=c) { ...... }//编译错误其实上面是想做一个比较操作,但是由于手误,写成了赋值操作,那么在编译的时候就会不能通过,能找出这个错误5、成员函数使用const(1)const用于成员函数是为了,该成员函数能作用于const对象上
class Demo{ void print(){cout<<"success"} }; ...... Demo obj; obj.print()//正确,可以调用 const Demo obj2; obj2.print()//错误,不能调用假如,把上面函数声明为const
void print()const{cout<<"success"} ...... obj2.print()//正确,可以调用(2)const成员函数重要的原因第一:可以使类的接口比较容易理解,因为可以知道,哪个函数能改动对象内容,哪个函数不能改动(const成员函数内部,不能改动对象内容,非const成员函数内可以改变);第二:使操作const对象成为可能,正如条款20所述,改善C++程序效率的一个办法是使用传指向常量的引用或指针,而这一计算的前提是,我们拥有const成员函数来处理取得的const对象;下面代码可以体现这一点:
class TextBlock{ const char& operator[](size_t position)const{ return text[position]; } private: string text; }; ...... void print(const TextBlock& ctb){ cout<<ctb[0];//传进来的参数是const对象,只有const成员函数才能处理,而operator[]是const成员函数 }(3)成员函数仅常量性不同,也可以被重载(不包括返回值是否为常量)考虑以下class:
class TextBlock{ const char& operator[](size_t position)const{ return text[position]; } char& operator[](size_t position){ return text[position]; } private: string text; }; ...... TextBlock tb("hello"); cout<<tb[0];\\调用非const成员函数operator[] const TextBlock ctb("hello"); cout<<ctb[0];\\调用const成员函数operator[]再考虑以下例子
cout<<tb[0];\\正确,读一个非const对象 tb[0]='x';\\正确,写一个非const对象 cout<<ctb[0];\\正确,读一个const对象 ctb[0]='x';\\错误,ctb[0]返回类型是const注意,
ctb[0]='x'错误的原因只因返回类型所致,调用[]操作符本身无问题;同时也要注意,非const的operator[]这个版本返回类型是char&,并不是char,如果是char,那么tb[0]=’x’`无法通过编译,那是因为,如果函数的返回类型是个内置型,那么改动函数的返回值从来不合法;(4)编译器强制实现bitwise constness,但怎么实现概念上的constness对于const修饰的成员函数分为两种观点: logic constness and bitwise constness.bitwise constness:它不更改对象的任一bit,即const成员函数不更改对象内的任何非静态成员变量;不幸的是,很多不遵守bitwise constness定义的成员函数也可以通过bitwise测试。特别是,一个“修改了指针所指向的数据”的成员函数,其行为显然违反了bitwise constness定义,但如果对象中仅包含这个指针,这个函数也是bitwise const的,编译时会通过。这种情况,是反直观的,考虑以下代码
class CTextBlock { public: ...... char& operator[](std::size_t position)const//bitwise constness声明,但其实不合适 {return pText[position];} private: char* pText; }; 我们可以这么做: const CTextBlock cctb("hello"); char* pc = &cctb[0]; *pc = 'J' //现在cctb为"Jello"虽然operator[]实现的代码并不改变对象的成员变量ptext,但是通过指针我们终究是改变了其对象的内容;这种情况,推出来了logical constness,这一派认为,一个const成员函数可以修改它所处理的对象内的bit,但只在客户端侦测不出的情况下才得如此;众所周知,我们在const成员函数中不能修改成员变量,但当需要修改时就需要另外一个关键字—mutable. mutable释放掉non-static成员变量的logical constness约束(编译器认定的,即在const内不能修改成员变量,这时就需要mutable;考虑以下代码:
class CTextBlock{由于length是const成员函数,所以在内部改变成员变量textLength、lengthIsValid是不合法的,但是单我们在成员变量名前加上mutable,在const成员函数内部改变成员变量,编译器就可以通过;(5)在非const成员函数内调用const成员函数,避免代码过度重复
public:
int length()const;
private:
char* pText;
mutable int textLength;
mutable bool lengthIsValid;
};
int CTextBlock::length()const
{
if(!lengthIsValid)
{
textLength = std::strlen(pText);
lengthIsValid = true;
}
return textLength;}
class TestBlock从上面代码中可以看出,代码的重复度十分高,为了避免这中情况,我们可以在非const成员函数内调用const成员函数,来实现非const成员函数,这样就可以避免代码的重复性;下面代码实现:
{
private:
string text;
public:
...
const char& operator[](size_t position) const
{
…
return text[position];
}char& operator[](size_t position)
{
…//操作跟上面相同
return text[position];
}
};
char& operator[] (size_t position) { return const_cast<char&>( static_cast<const TestBlock&>(*this)[postion] ); }上述代码有两个转型动作,(*this)转换为const TestBlock类型,假如不转换,编译器会调用非const成员函数,即自己本身,这样是个死循环;第二次是将返回类型转换为非常量char&,const_cast可以去除常量性;注意:不能在const成员函数内实现非const成员函数,即上述避免代码重复性的操作,不能反向进行参考:Effective C++ 3rd(侯捷译)、C++ Prime 4rd注:转载请注明出处/article/9883119.html
相关文章推荐
- c++ primer学习笔记
- C++ 迭代器
- C语言代码统计工具的源程序
- C++ 初始化列表
- C++Primer学习笔记之变量和基本类型
- Effective C++——条款19(第4章)
- Effective C++——条款18(第4章)
- 贝格尔编排法之C++版
- C++输入输出知识
- 为什么C++ 不叫++C?
- C++入门经典 笔记 (第十三章)高级引用和指针
- C语言实现栈操作
- 华为OJ题库-C++实现蛇形矩阵
- [JNI] Java 调用 C++ dll
- JNI开发之 c++输出日志到Logcat
- c++虚函数机制
- C++基础---函数指针
- python类变量与 C++的静态变量并不等效
- C++基础---有返回值类型函数(指针函数)
- 继承关系中的虚函数表