淘先锋技术网

首页 1 2 3 4 5 6 7

一、中心思想

1、将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、函数返回类型、成员函数本体;

2、编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”;

3、当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。


二、简述

1、面对指针,可分为一下两种情况:

(1)出现在星号左边,=》被指内容是常量;

一下两种形式是等价的:

void f1(const Widget* pw);

void f1(Widget const* pw); 

(2)出现在星号右边,=》指针自身是常量。两边都出现的话,被指内容和指针自身都是常量。


2、面对迭代器(const_iterator)

std::vector<int> vec;

(1)表示迭代器不得指向不同的东西,但它所指的内容是可以改变的

const std::vector<int>::iterator iter = vec.begin();

*iter = 10;

++iter;   //error, iter是const

(2)表示所指的的内容是不可改动的

std::vector<int>::const_iterator cIter =  vec.begin();

*cIter = 10    //error,*cIter是const

++cIter;


3、面对返回值

主要作用:

    降低用户错误而造成的意外。例如:把“==”键入成“=”。

e.g

class Rational{......}

const Rational operator* (const Rational& lhs, const Rational& rhs)

int main()

{

    Rational a, b, c;

    //若无const此语句是合法的,但是内置类型则一定是不合法的。。但是依据C++潜在规定,为了避免无端地与内置类型 的“*”不兼容,在函数前面加上const

    (a*b) = c;        

    //同时也能预防将“==”键入成“=”

    if(a*b=c)  ......

}


4、const成员函数

(1)两个成员函数若只是常量性不同,则可以被重载

const成员函数的重要性:

    1)使得class的接口比较容易理解,知道哪个函数可以改动对象的内容,哪个不可以

    2)使得“操作const对象”成为可能

e.g

#include<iostream>

using namespace std;

class TextBlock
{
public:
	TextBlock(std::string a):text(a){}
	const char& operator[](std::size_t position) const  //针对const对象
	{
		return text[position];
	}
	char& operator[](std::size_t position)  //针对非const对象
	{
		return text[position];
	}
private:
	std::string text;
};

int main()
{
	TextBlock tb("Hello");
	std::cout << tb[0];
        tb[0] = 'X';

	const TextBlock ctb("World");
	std::cout << ctb[0];
        ctb[0] = 'X';  //错误!!不能写一个const TextBlock
}

note:

两个成员函数都返回的都是引用,其中非const版本的是char& , 这样返回的是tb.text[0]d的引用,这样的话可以对其的值进行改变;

若返回值的类型是char,则不能对其进行重新赋值。


(2)bitwise constness和logical constness

前者认为,成员函数只有在不更改对象的任何成员变量时,也就是不更改对象内的任何一个bit,这样才可以说是const;

note:

1)许多成员函数虽然不是组具备const性质却能通过bitwise测试;

 
class CTextBlock
{
public :
	CTextBlock():pText(new char[100]) {}
	//const char& operator[](std::size_t position) const  //针对const对象
	//{
	//	return pText[position];
	//}
	char& operator[](std::size_t position)  //针对非const对象
	{
		return pText[position];
	}
	char& operator[](std::size_t position) const
	{return pText[position]; }
	~CTextBlock()
	{
		delete[] pText;
	}
private:
	char* pText;//此类只包含了指针成员,不同于上述的std::string 成员
};
int main()
{
    const CTextBlock cctb("Hello");
    char* pc =  &cctb[0];

    *pc = 'J';  //内容变为“Jello”
}


上述class只有指针成员pText,不同于之前的类TextBlock,用户并未改变该成员,但是却能改变所指内容的值

,但是仍然能逃过bitwise constness的测试,属于logical constness。

2)mutable:释放non-static成员变量的bitwise constness(因为编译器执意要bitwise constness,所以先释放bc)

class CTextBlock
{
public :
        ......
          
	std::size_t length() const;

private:
	char* pText;//此类只包含了指针成员,不同于上述的std::string 成员
	mutable std::size_t textLenth;
	mutable bool lengthIsValid;//mutable 使得在const的成员函数中可以改变这些成员变量
};

std:: size_t CTextBlock::length() const
{
	if (!lengthIsValid) {
		textLenth = std::strlen(pText);
		lengthIsValid = true;
	}
	return textLenth;
}


(3)在const和non-const成员函数中避免代码的重复

由于重载的const和non-const版本的成员函数有许多重复的代码,所以尽量用一次编写的代码使用两次

1) 可以用const的版本实现non-const的版本,反之则不可以

class TextBlock
{
public:
	......
	const char& operator[](std::size_t position) const
	{
		......
                return text[position];
	}
	char& operator[](std::size_t position)
	{
		
    return 
     const_cast<char&>(
     static_cast<const TextBlock&>(*this)
    [position]
            );

	}//运用const operator[]实现出non-const版本,反之则不行
private:
	std::string text;
};

note:

此类有连个转型动作:

1、static_cast: 将普通对象加上const属性,使之可以调用const版本的成员函数;

2、const_cast: 去除返回值的const属性