本人是一名在校大学生,此博客只为个人学习而用,不做商用!(反正也没人用)
如有错误,还请包含,顺便私聊一下我,要不然错漏百出的博客要被人笑话了2333333
在最近的c++之旅中,我多次看到const,一开始并没有太多关注,但是到了后来const的用法越来越复杂,我意识到了一点———我tmd已经忘了const怎么用了,忘了const的用法。所以,这次研究一下const。
-
const与指针
当处理const指针时,编译器将努力避免存储分配并进行型常量折叠。
常量折叠:在编译时间简单化常量表达的一个过程。简单来说就是将常量表达式计算求值,并用求得的值来替换表达式,放入常量表。可以算作一种编译优化。
在数组中,我们经常见到这样的写法。
const int ten=10; int a[ten];
这种写法,便是常量折叠。
我们在使用const来修饰指针时,面临着两种选择。
int *const p;//修饰指针 ,所以这个指针是const类型的。
int const *q;//修饰指针所指的内容
const int *q;
//q是一个指向恰好是const的int的普通指针
接下来我们写一段简单的代码来看看二者的不同。
#include<iostream>
using namespace std;
int main(void)
{
int a[] = {0,1,2,3,4,5,6,7,8,9};
int b[] = {1,2,3,4,5,6,7,8,9};
int *const p=a;
int const*q;
cout << "p=" << *p << endl;
q = b;
cout << "q=" << *q << endl;
q = a;
cout << "new q=" << *q << endl;
*p = 5;
cout << *p << endl;
p = b;//Error
*q = 5;//Error
return 0;
}
在出现Error之前的结果:
定义的p指针,是一个const指针,所以在经过初始化之后,p不能被改变;
定义的q指针, 是一个指向const数据类型的指针,其指向内容是无法更改的。
2.类与const与引用
之所以在这里加上“引用”,是因为我就是被引用和const搞烦的。并且引用在函数参数以及返回值上和const有很多的操作配合,因此我在这里带上引用,一起来讨论讨论。
-
首先讲小结:
const成员函数可以访问非const对象的非const数据成员、const数据成员,也可以访问const对象内的所有数据成员;
非const成员函数可以访问非const对象的非const数据成员、const数据成员,但不可以访问const对象的任意数据成员;
-
类里的const
常数表达式使用常量的地方之一是在类里。但这不是我们想讨论的重点,我觉得重点应该放在成员函数的const及引用上。
首先我们先复习一下引用及其物理意义。
引用在定义时与定义指针相似,只是用&代替了*。其物理意义在地址层面上一样的,都是与原对象/变量相同的地址。但引用实质上是一种“马甲”,也就是说,在传递参数的时候,引用并没有像按值传递那样刻录副本,也没有像指针那样新建了个指针变量去指向原变量。
使用引用的意义,更多是为了节省时间。在进行传参或者返回值得时候,不使用引用的函数,会进行两次复制,首先是被复制到一个临时位置,再使用这个临时位置赋值给参数或者返回值。但是使用引用,只需要进行一次复制就可以完成这项工作。
引用是一种换了个“马甲”的本身,在物理层面上也只是苦主本体罢了。(为什么我脑子里突然出现了苦主两个字?)
-
const对象和成员函数
const修饰成员函数的返回值
#pragma once
class test
{
private:
int a;
const int b;
public:
test();
~test();
const int show(int x);//const修饰成员函数的返回值
};
在这里,const实际上是没有用处的,因为它修饰的是返回值为const,但是按值传递的返回值并无太大意义。所以这时,const可加可不加。
const成员函数
const成员函数的定义其实非常简单,但它不是仅仅直接把const放在函数前就可以。当然你放在函数前只是表明它的返回值为const,并不是这个成员函数本身是const的。
定义const成员函数:
#pragma once
#include<iostream>
using namespace std;
class test
{
private:
int a=1;
const int b=19;
public:
test();
~test();
const int show(const int q,int x);//const修饰成员函数的返回值
int show(const int z,int s) const;
};
我们没发现非const成员函数和const成员函数有什么不同点,相反现在看到的都是他们所拥有的共同功能——调用const数据和非const数据。
但是从他的调用来看,我们则可以看到一些端倪。
//test.cpp
#include "test.h"
test::test()
{
a = 2;
}
test::~test()
{
}
const int test::show(const int q,int x)
{
cout <<"a="<< x << endl;
cout <<"b="<< q << endl;
return 0;
}
int test::show(const int z, int s) const
{
cout << "b=" << z << endl;
cout << "a=" << s << endl;
return 0;
}
#include"test.h"
int main(void)
{
const test test1;//const对象
test test2;//非const对象
test1.show(1, 1);
test2.show(1, 1);
system("pause");
return 0;
}
运行结果:
我们注意到,非const对象调用了非const成员函数,const对象调用了const成员函数。
那么const对象能调用非const成员函数,非const对象能调用const成员函数吗?
前者可以,后者不行。
代码不贴了,懒。
当const遇到引用,又会碰撞出什么火花呢??
首先我们先看看有哪些用法
- int const& 和 const int&
-
const int& f() const
首先来看第一个,这个其实是一个意思,我估计大家也都明白这点,所以我们直接跳过,来看看第二个是什么意思。
如果真的不知道,那么就阅读这里吧:
int const &和const int&是一个意思,都是表示是一个const的int类型。
const int &f()const,我们先从后面入手,那么很简单:第二个const是为了使函数能够被const和非const对象调用,且不会在函数调用中发生改变数据的行为。引用就很简单,告诉我们以及计算机,将要返回一个int类型的引用。最后就是这个返回的引用是不允许被修改的,是属于const类型的。