`
yidongkaifa
  • 浏览: 4051550 次
文章分类
社区版块
存档分类
最新评论

C++中const用法总结

 
阅读更多

C++中用法总结

1.1.1. 定义普通常量

使用#define来定义常量也是常用方法,但const也可以用来定义常量,在[Effective C++]中建议使用const代替#define来定义常量,因为const定义的常量具有类型信息,而宏没有,所以使用const定义的常量在进行赋值操作时编译器会进行更严格的类型检查,是类型安全的。

const double PI = 3.1414926;

const int POOL_SIZE = 20;

定义常量有三种方法:宏、const、enum,其中宏应该尽量避免,而const与enum也各有优缺点,最大的区别就是enum只能用于定义整数,而不能定义浮点数;而对于定义逻辑关系较近的一组整数时比较适合使用enum,也可以考虑使用类代替enum(参见[??])。

常量必须在定义时进行初始化,之后便不能再赋值。说它不能被赋值并不是说常量的值是绝对不会改变的,只是说不能直接赋值,但可以通过指针及强制类型转换、const_cast是可以改变常量的值的。

#include

using namespace std;

int main( void )

{

const int ci = 5;

const int* cpci = &ci;

int *pci = (int*)&ci;

cout<<"cpci = "<

return 0;

}

输出结果:

cpci = 002DFAC8, pci = 002DFAC8

ci=5, *cpci=1, *pci=1

ci=5, *cpci=2, *pci=2

ci != *cpci

之所以使用ci直接输出变量的值时显示其值始终没有改变,但通过指针间接显示出来的值是改变了,而且输出结果的最后一行很奇怪,ci的值与*cpci的值居然不相等,只因为编译器在编译时进行了优化,将代码中的ci直接替换成了5,与宏替换是相同的效果,而指针的值则是实际内存中的值。

所以,千万不要试图使用指针强行改变const变量的值,否则程序可能表现出错误的行为,而且查找起来这种错误非常困难。在gcc 4.3.4和visual C++ 2010中均默认打开了对常量的优化选项,目前还没找到关闭该优化的命令行选项,一定不要自作聪明去改const变量的值。

1.1.2. 修饰指针

把const与指针放到一起,很多人便会想到一个绕口令“指针常量与常量指针。“指针常量”即一个指针变量,该变量不能被赋值,而指针指向的内存单元的内容是可以改变的;“常量指针”即一个指向常量的指针,指针变量本身可以赋值,而指针指向的内存单元的内容是不可以被重新赋值的。

char a = 'A', b = 'B';

const char* ptoc = &a; // 常量指针

*ptoc = 'C'; // 改变指针指向内存单元的内容,不可以

ptoc = &b; // 改变指针的值,可以

char* const cp = &a; // 指针常量

cp = &b; // 改变指针的值,不可以

*cp = 'D'; // 改变指针指向内存单元的内容,可以

const char* const cptoc = &a; // 指向常量的指针常量

*cptoc = 'E'; // 不可以

cptoc = &b; // 不可以

const是修饰类型还是修饰指针,要看const的位置,放在*前就是修饰数据类型,放到*后就是修饰指针,const char和char const是一样的。

建议:在不打算修改数据内容的时候都将指针定义成常量指针,不打算指针本身被修改的场合都定义成指针常量。尽可能地多用const,用错了没关系,编译器会提示你的,只要能够编译通过,就不会因为用错const而导致程序逻辑错误,应该说const负作用极小。

1.1.3. 修饰类成员常量

当使用const修饰类成员变量时便定义了常数据成员,它的使用与使用类外定义的常量本质上并没有什么区别,在这里只想指出一点:有网友提到const数据成员只能被const修饰的函数使用这是没有根据的,是错误的。

1.1.4. 修饰类成员函数

const修饰成员函数语法:

class Socket

{

public:

typedef unsigned short socket_port_t;

socket_port_t LocalPort( void ) const

{

++readCount;

return _port;

}

private:

socket_port_t _port;

mutable int _readCount;

};

使用const修饰的成员函数不能修改类的成员变量,如成员_port,而且只能调用成员类对象const函数,但有个例外,就是mutable修饰的成员变量可以在const修饰的成员函数中被修改,如_readCount。

另外,const只能修饰非静态函数。

建议:将所有不改变对象状态的函数都使用const修饰符标识,以提高程序的可读性。其实,头文件就是最好的类接口的说明文档,越多的提供信息就能使程序的可读性越好,越利于维护。看到成员函数的const修饰符,读者便立即明白该函数不会改变程序的状态,这也有利于当程序状态出现异常时的问题定位。

1.1.5. 修饰类对象、对象引用或对象指针(常量指针)

当const修饰自定义的类对象时,与修饰C++内置类型的变量的思想是一致的,但稍有不同,除了不能被赋值外,还不能调用没有使用const修饰的非静态成员函数。当const修饰类对象引用、指针时限制是一样的,因为引用本身与直接使用该变量实质上没有区别,而使用指针只是将.操作符改为了->本质上还是一样的

const std::string hello = “Hello from Noock Tian;

std::cout<

hello = "Hi"; // 不可以赋值

hello.push_back("!"); // 不可以

1.1.6. 修饰函数参数

const修饰函数的例子是很常见了,表示函数的参数在函数体内不会被意外修改,一般用于修饰输入参数,例如标准库中的字符串连接函数。str1是输出参数,其内容会被修改,而str2为输入参数,其内容不会修改。

char* strcat(char* str1, const char* str2);

实际上在说到const用法一开始就提到,const只是一种声明,但并不能保证,例如strcat函数虽然声明了str2为const char*型,但并不能保证内部绝对不会修改str2的内容。但const从语言本身提供了一种编写自描述性代码的方法,只要使用函数与实现函数的双方都达成一致的约定,按照契约编程,我们就可以认为const修饰的类型在函数体内不会被修改,这与const修饰类成员函数一样,可以提高软件的可读性。

1.1.7. 修饰函数返回值

const可以用于修饰任何类型,只要返回值类型不是void,const就可以用来修饰返回值的类型。但实际上const用于修饰非引用的返回值类型是没有意义的,因为返回值一般都会被赋值给另一个变量,此时用于传递返回值的对象已经被销毁,修饰返回值类型的const的作用也就终结了。

当返回值是引用类型时,如果该引用的值不希望被修改是可以声明为常引用的,例如:

class Socket

{

public:

const string& IP( void ) const{ return _ip; }

private:

string _ip;

};

Socket sock;

string& ip = sock.IP(); // 不可以

const string& ip2 = sock.IP(); // 可以

string ip3 = sock.IP(); // Socket::_ip被复制,可以

此处,为了减少构造临时变量,将IP函数返回值定义为引用类型以提高程序运行效率,但为了保护内部状态不会被客户端代码意外,返回值使用const修饰为常引用。但是,如果对于软件安全性较高的场合,最好不要定义为引用,因为恶意的客户端代码是有可能修改Socket::_ip的值的。

在C++中赋值运算符反默认返回值都是引用,但笔者认为定义为常引用更为合适,例如:

int main( void )

{

int a = 1,b = 2,c = 3,d = 4;

((a=b)=c)=d;

cout<<”a=”<

return 0;

}

输出结果:

a=4, b=2, c=3, d=4

显然,在实际工程中谁也不会写出这样的代码,这段代码却是合法的,无疑这给程序员多了一种出错的可能,如果把赋值运算符的返回值定义为常引用,则会减少程序员出错的机会,例如[??]:

class Object

{

public:

const Object& operator=(const Object& a) { return *this; }

};

int main( void )

{

Object a, b, c, d;

a = b = c = d; // 可以

((a=b)=c)=d; // 不可以

return 0;

}

在gcc 编译时则会出现错误提示:

error: passing ‘const Object’ as ‘this’ argument of ‘const Object& Object::operator=(const Object&)’ discards qualifiers.
当然,不同的编译器可能错误提示不同。

分享到:
评论

相关推荐

    c++中const用法总结

    c++中const用法总结,心血之作。希望对小伙伴们有所帮助

    C++中const用法总结.doc

    C++中const用法总结.doc C++中const用法总结.doc 1. const修饰普通变量和指针 2. const修饰函数参数 3. const 修饰函数返回值 4. const修饰类对象/对象指针/对象引用 5. const修饰成员变量 6. const修饰成员...

    C++中const用法全解

    const在C++中占有重要作用,属于小兵立大功的典型,本文档详细介绍了如何使用const

    c++中const用法详解

    c++中const用法详解,引用大量实例进行分析!

    C/C++中CONST用法总结(推荐)

    主要介绍了C/C++中CONST用法总结(推荐),包括const常量与define宏定义的区别介绍,非常不错,具有参考借鉴价值,需要的朋友参考下吧

    C++中const用法.pdf

    C++中const用法.pdf

    关于const在C++中的用法

    关于const在C++中的用法,绝对有意义的总结!

    c++里const用法归纳

    C++里对const的常用用法和总结,很不错,讲的很详细。

    c++中的const用法总结

    本资源总结了c++中的const用法,提供初学者学习。

    C++ 中const总结

    C++ 中const总结 const 限定符把一个对象转换成一个常量,如 const int bufSize=512; 申 明 bufSize 的时候,如果不将它初始化,那么编译器会报错:const object must be initialized if not extern。因为 bufSize ...

    C++ const应用总结

    C++ learning ---const用法总结,将平时不同情况的const用法,进行了详细的总结。是学习C++的好帮手

    Const 用法小结

    C++中的各种Const用法小结:const常量,const 修饰类的数据成员等等

    C++中const的用法

    C++const用法详解。这里可以学到C++const的一些用法。

    C++中const用法小结

    const在C++中使用十分广泛,不同位置使用的意义也不尽相同,所以想写篇文章对其做一个总结。 首先,明确const是“不变”这个基本意义,但是不变不意味着什么都不变,下面将会看到。 1. const与变量 基本原则:const...

Global site tag (gtag.js) - Google Analytics