您的位置:首页 > 编程语言 > C语言/C++

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 temporary
ref2实际上是绑定到一个临时变量上,如果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是个const
4、函数声明,包括函数返回值、参数使用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{
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;}
由于length是const成员函数,所以在内部改变成员变量textLength、lengthIsValid是不合法的,但是单我们在成员变量名前加上mutable,在const成员函数内部改变成员变量,编译器就可以通过;(5)在非const成员函数内调用const成员函数,避免代码过度重复
class TestBlock
{
private:
string text;
public:
...
const char& operator[](size_t position) const
{

return text[position];
}char& operator[](size_t position)
{
…//操作跟上面相同
return text[position];
}
};
从上面代码中可以看出,代码的重复度十分高,为了避免这中情况,我们可以在非const成员函数内调用const成员函数,来实现非const成员函数,这样就可以避免代码的重复性;下面代码实现:
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: