一.const

const很初学者看到这个东西都会很头疼,不知道究竟是什么东西,那么久简单地一句话总结一下,这句话 不一定对,只是方便记忆和理解。

1.const是什么究竟怎么看

const:const先作用于左边,若左边没有东西,就便会作用于右边。(重点)

我们来看几个例子

const int

int const //这以上两个就不多做解释,他们是一样的

const int* //const作用于右边,所以是指针指向的内容不可改变

int* const //const作用于左边,所以是指针不可改变,也可叫常量指针

const int* const //将上面两个综合一下

好的,新手肯定说哦我的头已经开始晕了,咱们就拿那句话就能得出结论(看注释)。就拿那简单的一句话来看,百分之99的const语句都不会出错,就不用看某某某老师,某某某教育机构的长篇大论,越听越迷糊。

2.顶层const与底层const

(1)如何看是顶层还是底层const

还是用我自己的话来说,它方便大家记忆和理解

只要const是修饰的对象或者类型本身,那么这个const就是顶层const。(重点)

我们还是举例来说明一下

const int* const

//左边的const修饰的是这个指针指向的类型并不是这个指针对象座椅它不是顶层const而是底层const

//右边的const修饰的是这个指针对象本身所以它是顶层const

//总体而言他是个既是底层有是顶层的const

const int

//这种const永远是顶层const

const int&

//因为& 其实就是指针的一种语法糖,所以这种const永远都是底层const,引用永远是没有顶层const

(2)有何作用

底层const会影响传入函数的对象,顶层const却不会影响,在函数传参时顶层const会被忽视掉的。 (重点)

我们还是举例来说明一下,毕竟看这干条条的话换谁都头疼

void Fun(const int a)

{

}

void Fun(int a)

{

}

//当我们生成时会发生以下报错

// error C2084: 函数“void Fun(const int)”已有主体

会发生这种错误,为什么呢?我们知道了 const int 是一个顶层const,所以这两个函数他们的传参类型其实是相同的,因为const在传参时会被忽略掉,这两个函数类型都是 void(int)这种函数类型所以,报错了。咱们再看一下这个例子。

void Fun(const int* a)

{

}

void Fun(int* a)

{

}

这回就可以完美生成没有报错,因为我们知道这个const是个底层const可以进行函数重载,如果我们把第一个修改成 void Fun(int* const a)那么他又会报错无法进行函数重载,因为他变成了修饰这个指针对象本身的顶层const,大家有兴趣可以试一试。

二:const的几个用处

const的用法和用处很多,尤其是函数重载,成员函数这里有很多疑惑的地方,我们来一一举例出const的用法。ps(上一部分已经举例了一个东东,但是我已经懒得排版了,大家不要忘了上面的东东)。

1.全局变量相关

大家都知道全局变量他是有静态存储区的,他在程序开始时分配空间,在程序结束时析构掉。不多说了,上例子吧。(这期博客确实有点无聊,都没有有趣的例子是吧)

#include

extern int a = 1;//与int a=1;没有区别

int main()

{

std::cout << a << std::endl;

}

extren是干什么的,那我们这么写。

#include

extern int a;

int main()

{

std::cout << a << std::endl;

}

这个a是没有定义的,他只是个声明,extern他是一个链接的一个关键字,相当于一个外部链接的作用,就是我们在同项目中另一个文件定义一个全局变量,这里将会打印出那处的值。我们来看。

我们可以清楚的看到打印出了100,这个就是extern的作用 。

但const的全局变量,它默认是内部链接,如果不知道什么是链接我可能也会出一篇博客来讲,总之期待吧,可能。那我们改一下会怎么样呢?

我们会获得到一个这样的报错: error LNK2001: 无法解析的外部符号 "int const a" (?a@@3HB)因为我们没办法获得到外部链接,不过再在左边的文件的const前加一个extern他就又可以正常输出了,这是const一个比较隐藏的小知识点。

2.const reference 延续临时变量生命周期

我们还是直接看例子吧

#include

#include

void* operator new(size_t size)

{

std::cout << "new" << std::endl;

return malloc(size);

}

void operator delete(void* m, size_t size)

{

std::cout << "delete" << std::endl;

free(m);

}

const std::string& Print(const std::string& s)

{

std::cout << s << std::endl;

std::cout << "I also alive" << std::endl;

return s;

}

int main()

{

Print("KNGG");

return 0;

}

它的输出结果是:

我们可以看到,临时变量的生命周期被延长了,到Print函数结束后才被“杀”掉,它有效的延长了临时变量的生命周期,要不然他该在传入后就被“杀”掉了。

3.类成员函数const重载的本质

别说了,上代码!

#include

#include

class vector

{

private:

int x, y;

public:

void Print();

void Print()const;

};

int main()

{

vector vec;

vec.Print();

return 0;

}

我们都知道在成员函数的结尾加上const可以进行重载,但实质上是怎么一回事呢,它为什么能重载?

实质上这种成员函数在编译后会先变为非成员函数,并且会有个name mangling的过程就是改名,在编译器解析之后咱们的成员函数就会边长以下模样:

void Print(vector* const this);//1

void Print(const vector* const this);//2

参考前面顶层底层const所以它可以重载。

我们写一个代码来当做课后作业吧(装起来了)也是成员函数的const重载

#include

#include

class vector

{

public:

std::vector ve;

public:

void Print(std::size_t size)const

{

std::cout << (*this)[size] << std::endl;

}

const int& operator [](std::size_t size)const

{

return ve[size];

}

int& operator[](std::size_t size)

{

return const_cast(const_cast(*this)[size]);

}

};

int main()

{

vector vec;

vec.ve = { 1,2,3,4,5,6 };

vec.Print(3);

return 0;

}

看能不能理解这一段代码,我过两天会把解析发在评论区中。

总结

ok以上就是const大概的内容了,当然还有很多东西没提到,也许也有错的地方还是那句话,欢迎大家来指正,谢谢大家看到这里。