摘自Effective c++关于const 的用法介绍:
1、对于基本类型声明:
const int i = 1;
int const i = 1;
两种写法本质都是标准const变量声明加初始化,i为常量,不可修改。因为默认为内部连接,所以必须被初始化,其作用域为此文件,编译器经过类型检查后直接用100在编译时替换。//与#define不同的是const在编译期间被替换,也就是说记号名称被写入了符号表。
extend const int i = 100;
const改为外部连接,作用域为全局,在编译时分配内存。可以不初始化,仅作为声明,编译器将认为在别的地方进行初始化。
const int arr[] = { 1, 2, 3, 4};
struct S { int a, b};
const S s[] = { ( 1, 2), ( 3, 4) };
两种都是常量集合,在编译期间会被分配内存,在编译期间无法使用其值,例如 int arr_s[ arr[2] ] 将报错,提示不能找到常量表达式。
2、const修饰指针
引述effective C++,如果const出现在*号左边,修饰的是指针指向的对象,被指对象是常量,即对象不可修改。如果const出现在*号右边,修饰的是指针本身,指针本身是常量,即指针不能再指向别的内存。如果const出现在*号两边,则指针和被指对象均是常量。
const int *p = &x; //x是常量
int const *p = &x; //x是常量
int* const p = &x; //指针p是常量
const int * const p = &x; //指针p和变量x均是常量
3、const修饰函数参数
这是const的最广泛的用途之一。
void function(const int param); //无意义,pass-by-value,此处传递的是实参的副本
void function(const int* p); //指针指向的对象在函数体内不可被修改
void function(int* const param); //无意义, 指针本身是常量
当参数为引用
void function(const CLASS_TYPE& param); //参数在函数体内不可被修改
void function(const TYPE& param); //参数为在函数体内为常量
4、const修饰函数返回值
const TYPE function(); //无意义,返回的是return expression的拷贝
const TYPE* function(); // const TYPE* p = function(); p指向的的内存内容不可修改
TYPE* const function(); //TYPE* const p = function(); 指针p本身是常量,不可再指向其他内存
const TYPE& function(); //返回的是常量值,且非常安全。
//安全性 例:有函数声明const Rational operator* (const Rational& lhs, const Rational& rhs);
if(a * b = c){....} //原意其实仅仅是想比较?
避免返回值被修改,上式非法。
5、const修饰类对象/类对象指针/类对象引用
当const修饰类对象时,对象为常量对象。表示此对象的任何成员都不能被修改。
常量对象的非常量成员函数都不能被调用,因为非常量成员函数有修改类成员的可能。
class A
{
public:
int function_1();
int function_2() const;
.....
};
const A Object_a;
Object_a->function_1(); //非法
Object_a->function_2(); //合法
const A* Object_b = new A();
Object_b->function_1(); //非法
Object_b->function_2(); //合法
6、const修饰类成员
class A
{
private:
const int a; //类成员为常量,不能被修改
...
public:
A(int r):a(r){} //常成员变量只能在构造函数的初始化列表中初始化
A(int r)
{
a = r; //error,这是赋值,不是初始化
}
...
};
7、const修饰类成员函数
const修饰类成员函数,则该函数不能修改类成员,也不能调用类的非const成员函数。
class A
{
...
int function() const; //function不能修改任何类成员,也不能调用非const类成员函数
...
};
根据6,const 对象/对象指针/对象引用 只能调用const成员函数。
注意:
两个函数如果只是常量性不同,可以被重载。
class TextBlock
{
...
public:
const char& operator [] (int position) const;
char& operator [] (int position);
...
private:
string text;
};
为了const和non-const成员函数中避免重复,可以在non-const成员函数实现中调用const成员函数。
class TextBlock
{
...
public:
const char& operator [] (int position) const
{
...
return text[position];
}
char& operator [] (int position)
{
return const_cast<char&>(static_cast<const TextBlock&>(this*)[position]);
}
...
private:
string text;
};
注意:
使用的是non-const成员函数调用const版本,因为const版本不会修改对象。反之,若const版本调用non-const版本,则对象在non-const版本中可能被修改,从而导致的连锁反应是const版本在调用non-const版本的过程中,对象可能被修改。
8、对于字符数组和临时对象
char* str = "hello world!";
str是常量字符数组,任何想对str进行修改的操作可以通过编译,但是会引起运行时错误。
若想修改字符数组,应该声明为 char str[] = "hello world!";
注意:
临时对象都是常量;
9、对于类型检查
可以将一个非const对象赋给指向const的指针,因为不能通过这个指针修改对象的值。不可以将一个const对象赋给指向非const的指针,因为可能通过从这个指针修改对象的值。若想后者合法,可以通过类型转换去掉const的常量性,语法如下:
const int i = 100;
int* pi = &i; //非法
int* pi = const_cast<int*>(&i); //const_cast 去掉了i的常量特性
#include <stdio.h>
#include <cmath>
#include <iostream>
using namespace std;
class Rational{
private:
int num,den;
public:
Rational(int n , int d = 1);
Rational();
void setData(int n,int d);
void simplify();
void show();
bool operator<(const Rational &);
bool operator<=(const Rational &)const;
friend bool operator>(const Rational &,const Rational &);
friend bool operator>=(const Rational &,const Rational &);
bool operator==(const Rational &)const;
bool operator!=(const Rational &)const;
friend Rational operator+(const Rational &,const Rational &);
friend Rational operator-(const Rational &,const Rational &);
friend Rational operator*(const Rational &,const Rational &);
friend Rational operator/(const Rational &,const Rational &);
Rational operator-();
operator double();
};
Rational::Rational(int n,int d){
num = n; den = d;
simplify();
}
Rational::Rational(){
num = 1;den = 1;
}
void Rational::setData(int n, int d){
num = n; den = d;
simplify();
}
void Rational::simplify(){
int min;
if(num < den)
min = num;
else
min = den;
for(int i = min;i >= 2;i--){
if(num%i == 0 && den%i == 0){
num = num/i;
den = den/i;
}
}
}
bool Rational::operator<(const Rational &r){
return num*r.den < r.num*den;
}
bool Rational::operator<=(const Rational &r)const{
return num*r.den <= r.num*den;
}
bool operator>(const Rational &r1,const Rational &r2){
return r1.num*r2.den > r2.num*r1.den;
}
bool operator>=(const Rational &r1,const Rational &r2){
return r1.num*r2.den >= r2.num*r1.den;
}
bool Rational::operator==(const Rational &r)const{
return num*r.den == r.num*den;
}
bool Rational::operator!=(const Rational &r)const{
return num*r.den != r.num*den;
}
Rational operator+(const Rational &r1,const Rational &r2){
Rational temp;
temp.num = r1.num*r2.den + r2.num*r1.den;
temp.den = r1.den*r2.den;
temp.simplify();
return temp;
}
Rational operator-(const Rational &r1,const Rational &r2){
Rational temp;
temp.num = r1.num*r2.den - r2.num*r1.den;
temp.den = r1.den*r2.den;
temp.simplify();
return temp;
}
Rational operator*(const Rational &r1,const Rational &r2){
Rational temp;
temp.num = r1.num*r2.num;
temp.den = r1.den*r2.den;
temp.simplify();
return temp;
}
Rational operator/(const Rational &r1,const Rational &r2){
Rational temp;
temp.num = r1.num*r2.den;
temp.den = r1.den*r2.num;
temp.simplify();
return temp;
}
Rational Rational::operator-(){
return Rational(-num,den);
}
void Rational::show(){
simplify();
cout<<num<<"/"<<den<<endl;
}
Rational:: operator double(){
return double(num)/den;
}
int main(){
Rational a(4,5),b(16,24),c;
a.show();
b.show();
if(a<b)
cout<<"a<b"<<endl;
else if(a == b)
cout<<"a==b"<<endl;
else
cout<<"a>b"<<endl;
c = a+b;
c.show();
c = a-b;
c.show();
c = a*b;
c.show();
c = a/b;
c.show();
c = -a;
c.show();
cout<<double(c)<<endl;
return 0;
}