const 限定符总结

来源:互联网 发布:株洲网络买花花店 编辑:程序博客网 时间:2024/06/10 11:41

这篇总结是对C++ primer一书中对const 零散知识点的归纳。

一、指针 和 const

1、指向的对象是 const

const double pi = 3.14;

const double a = 0;

const double *p2cd = π //ok

*p2cd = 42; //err: p2cd 指向的对象是 const

p2cd = &a; //ok: 允许对 p2cd 重新复制,p2cd 本身不是 const


double *p2d = π //err 不能把 const 对象的地址 赋值 给一个非 const 的指针

void *p2v = π //err 不能把 const 对象的地址 赋值 给一个 void * 指针,必须是 const void * 指针

const void *p2cv = π //ok


double dval = 3.14;

p2d = &dval;

p2cd = &dval; //ok 允许把非const 对象的地址 赋值 给指向 const 对象的指针

该操作的意义在于 不能通过 p2cd 来改变对象,但是我们可以通过 dval 或 p2d 来改变 dval,所以不能想当然的认为 指向 const 对象的指针此时指向是 const 对象。

我们可以用 “自以为指向的是 const 对象” 来理解 。


2、const 指针

指针本身不能修改。

int a = 1;

int b = 2;

int *const cp2i = &a;

cp2i = &b; //err

所以 const 指针只能在定义时初始化


*cp2i = 5; //ok 可以通过指针来改变对象,注意和 1 类比。


3、指向 const 对象的 const 指针

const double *const cp2cd1 = π //ok

const double *const cp2cd2 = &dval; //ok

允许把const 对象的地址 或 非const 对象的地址 赋值 给该类型指针


*cp2cd1 = 0; //err

*cp2cd2 = 0; //err

cp2cd1 = &dval; //err

cp2cd2 = π //err

既不能通过指针改变指向的对象,也不能改变指针本身


4、const + typedef

typedef int *p2i_type;

const p2i_type p1;

p1 的类型是什么呢?等价于  const int *p1,还是 int *const p1

//test

int i = 5, j = 3;
typedef int *p2i_type;
const p2i_type p1 = &i;

*p1 = 0; //ok
p1 = &j; //err

所以 const p2i_type p1  等价于 int *const p1 

原因把 typedef 当做文本扩展了,不同于 #define。


二、形参 和 const

1、非引用形参 和 const

int func(const int i) { ...... }

int func(int i) { ...... }  // redefinition of ‘int func(int)’ 

尽管第一个函数的形参是 const ,但是编译器却将其视为普通的 int 型。

这种用法是为了支持对 C语言 的兼容,因为在 C语言中,具有 const 形参 或 非const 形参并无区别。


2、引用形参 和 const

test1:
int incr(int &val)
{
return ++val;
}

int main(void)
{
short v1 = 0;
const int v2 = 42;

int v3 = 0, v4 = 0;


非const 引用实参只能与完全同类型的非const 对象关联

v3 = incr(v1); //err: invalid initialization of reference of type ‘int&’ from expression of type ‘short int’


也不能传递一个右值
v3 = incr(0); //err: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
v3 = incr(v1+v2); //同上
v4 = incr(v3); //ok
return 0;

}

test2: 接上例

int incr(const int &val)
{
return val;
}

const 形参 和 非const 形参 等价性仅适用于非引用形参,而有 const 引用形参的函数 和 非const 引用形参的函数是不同的。可以重载

test3:
应该将不修改相应实参的形参定义为const 引用,否则将限制该函数的使用。普通的非const 引用形参在使用时不太灵活,既不能用const 对象初始化,也不能用字面值或产生右值的表达式实参初始化。
下面的例子中这个函数 形参为string 类型,尽管函数中并没有修改该形参的值,这样的定义带来的问题是不能通过字符串字面值来调用该函数
string::size_type find_char(string &s, char c)
{

string::size_type i = 0;
while (i != s.size() && s[i] != c)
{
i++;
}
return i;
}


int main(void)
{
find_char("hello world", 'w'); //err: invalid initialization of non-const reference of type ‘std::string& {aka std::basic_string<char>&}’ from an rvalue of type ‘const char*’
return 0;
}

三、类数据成员 与 const & static 

类数据成员初始化方式 总结如下表:(该表来自网络)

类型 初始化方式

类内(声明)

类外(类实现文件)

构造函数中

构造函数的初始化列表

非静态非常量数据成员

N / C++11可设置默认值

N

Y

Y

非静态常量数据成员

/ C++11可设置默认值

N

N

Y (must)

静态非常量数据成员

N

Y (must)

N

N

静态常量数据成员

Y

Y

N

N


四、const 成员函数

1、如果函数被声明为 const 成员函数,那么函数定义时形参表后面也必须有 const。
class Sales_item
{
public:
bool same_isbn(const Sales_item& rhs) const;


private:
string isbn;
unsigned units_sold;
double revenue;
};


bool Sales_item::same_isbn(const Sales_item& rhs) const
{
return isbn == rhs.isbn;
}


2、在调用 const 成员函数时,隐含的this 形参将是一个 const Sales_itme * 类型的指针。
(普通成员函数 this 形参是一个 Sales_itme * 类型的指针)
所以 该类型的函数只能读取而不能修改 调用它们的对象的数据成员。
同理,const 对象、指向 const 对象的指针或引用都只能调用其 const 成员函数。


3、const 成员函数 可以重载 相同形参表的 非const 成员函数


原创粉丝点击