const的一些总结
const的一些总结
采用const符号常量写出来的代码更容易维护,有些函数只读不写:
1 常变量: const 类型说明符 变量名
2 常引用: const 类型说明符 &变量名
3 常成员函数: 类名::fun(形参) const
4 常量和指针
用法一:常量
const变量取代了C中宏常量的方式
const char ch;
char const ch;
上面二者是等同的,如果没有初始化编译会报错。也就是说一般情况下const常量在定义时必须初始化
不过在C++类中就不一定,例如
你定义了
class A
{
char const ch;
};
而没有使用类A定义任何对象和指针是不会报错的
但你一旦定义了构造函数
class A
{
public:
A(){};
char const ch;
};
就必须初始化,一般是在成员初始化列表或者构造函数里面初始化。记住const 常量要初始化。外部变量在其它文件申明不需要重新初始化
用法二:指针和常量
使用指针时涉及到两个对象:该指针本身和被它所指的对象。将一个指针的声明用const“预先固定”将使那个对象而不是使这个指针成为常量。要将指针本身而不是被指对象声明为常量,必须使用声明运算符*const。
(1) char *const cp; //到char的const指针,指针指向的对象不能变,但是可以修改对象的内容
int a = 9;
int * const p = &a;
*p = 10; //可以
int c = 0;
p = &c; //编译报错
(2)char const *pc1; //到const char的指针,这种看起来有点晦涩,一般使用下面一种方法申明
(3)const char *pc2; //到const char的指针(跟上一个声明是等同的),不能改变所指向对象的内容,但是可以重新指向其他对象
int a = 9;
const int *pNum = &a;
*pNum = 10; //编译无法通过
还有另外一种方式能够进行修改
void func(const int *pi)
{
//这里相当于重新构建了一个指针,指向相同的内存区域。当然就可以通过该指针修改内存中的值了。
int* pp = (int*)pi;
*pp = 100;
}
int a = 9;
const int *pNum = &a;
a = 25;
int *p = &a;
*p = 10;
通过其他指针操作a的地址还是可以改变a的内容的
int a = 9;
const int *pNum = &a;
//*pNum = 10;
const int b = 0;
pNum = &b;
这样是可以的,上面例子可以看到并不一定要指向const类型的变量哦,允许把非 const 对象的地址赋给指向 const 对象的指针,不允许把一个 const 对象的地址赋给一个普通的、非 const 对象的指针。
(4)const char * const pc2;//指向const chat的const指针,也就是指向常量的常指针,听这个名字你就知道了,只能乖乖的用,别想做啥了
上面内容可以有如下从右向左读的记忆方式记忆方式:
cp is a const pointer to char.
pc2 is a pointer to const char.
用法三:修饰函数返回值
可以阻止用户修改返回值。返回值也要相应的付给一个常量或常指针。
class A
{
public:
const char* fun()
{
char *p = new char('a');
return p;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A obj;
const char *p = obj.fun();
char *p2 = obj.fun();//报错
}
用法四:const修饰函数传入参数
将函数传入参数声明为const,以指明使用这种参数仅仅是为了效率的原因,而不是想让调用函数能够修改对象的值。同理,将指针参数声明为const,函数将不修改由这个参数所指的对象。
通常修饰指针参数和引用参数:
void Fun( const A *in); //修饰指针型传入参数
void Fun(const A &in); //修饰引用型传入参数
记起来一个有趣的问题
class A
{
public:
A(){};
A(const A a){};
const char* fun()
{
char *p = new char('a');
return p;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A obj1;
A obj2(obj1);
cout<<"Initialize obj2 success ."<<endl;
getchar();
return 0;
}
在vc2008上编译直接通不过,error C2652: “A”: 非法的复制构造函数: 第一个参数不应是“A”
可能与编译器有关。不过就算通过也是有问题的,因为类A的复制构造函数使用的值传递,使用复制构造时就会不停递归的调用复制构造
所以一般都会使用引用类型传参,大型对象还可以节省空间提高运行效率
下面还有个例子可以详解下:
class A
{
private:
int value;
public:
A(int n)
{
value = n;
}
A(A other)
{
value = other.value;
}
void Print()
{
cout<<value<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a = 10;
A b = a;
b.Print();
getchar();
return 0;
}
上述代码中,赋值构造函数A(A other)传入的参数是A的一个实例。由于是传值参数,我们把形参复制到实参会调用复制构造函数,
就会形成永无休止的递归调用从而导致栈溢出。因此 C++标准 不允许复制构造函数传值参数,在VS和GCC中都将编译报错。
用法五:const修饰成员函数(c++特性)
const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数;
const对象的成员是不能修改的,而通过指针维护的对象确实可以修改的;
const成员函数不可以修改对象的数据,不管对象是否具有const性质。编译时以是否修改成员数据为依据进行检查。
class A
{
public:
A(){};
void fun1()const{};
void fun2(){};
};
int _tmain(int argc, _TCHAR* argv[])
{
A obj;
obj.fun1();//正确,非常量对象可以调用常量函数。
obj.fun2() // 正确,非常量对象也允许修改调用非常量成员函数修改数据成员。
const A constObj;
constObj.fun1(); //正确,常量对象只能调用常量函数。因为不希望修改对象状态。
constObj.fun2(); //错误!常量对象的状态不能被修改,而非常量函数存在修改对象状态的可能,因此会产生语法错误
}
实际上,我们知道每个成员函数都有一个隐含的指向对象本身的this指针。而常量函数则包含一个this的常量指针。如下:
void fun1(const A* this) const;
void fun2(A* this);
也就是说对于常量函数,我们不能通过this指针去修改对象对应的内存块。但是,在上面我们已经知道,这仅仅是编译器的限制,我们仍然可以绕过编译器的限制,去改变对象的状态。看下面的代码:
void A::fun1() const
{
//给类A添加一个value成员
cout << "Value = "<< value << endl;
// 这里,我们根据this指针重新定义了一个指向同一块内存地址的指针。
// 通过这个新定义的指针,我们仍然可以修改对象的状态。
A* pA = (A*)this;
pA->value = 50;
cout << "A::fun1() called. value = "<< value << endl;
}
int main()
{
A a;
a.fun1();
return 0;
}
上面是可行的,不过一般不会这么做.有些编译器支持mutable变量,这样可以直接修改这个变量或者类成员
const 在c和c++中的区别
1. C++中的const正常情况下是看成编译期的常量,编译器并不为const分配空间,只是在编译的时候将期值保存在名字表中,并在适当的时候折合在代码中。在C中就不能使用const变量作为数组定义的长度,因为在C中在C中,const是一个不能被改变的普通变量,既然是变量,就要占用存储空间
2. 在C语言中: const int size; 这个语句是正确的,因为它被C编译器看作一个声明,指明在别的地方分配存储空间.但在C++中这样写是不正确的.C++中const默认是内部连接,如果想在C++中达到以上的效果,必须要用extern关键字.即C++中,const默认使用内部连接.而C中使用外部连接.
(1) 内连接:编译器只对正被编译的文件创建存储空间,别的文件可以使用相同的表示符或全局变量.C/C++中内连接使用static关键字指定.
(2) 外连接:所有被编译过的文件创建一片单独存储空间.一旦空间被创建,连接器必须解决对这片存储空间的引用.全局变量和函数使用外部连接.通过
3. C++中,是否为const分配空间要看具体情况.如果加上关键字extern或者取const变量地址,则编译器就要为const分配存储空间.
4. C++中定义常量的时候不再采用define,因为define只做简单的宏替换,并不提供类型检查
const的一些总结的更多相关文章
- openssl 1.1.1 reference
openssl 1.1.1 include/openssl aes.h: # define HEADER_AES_H aes.h: # define AES_ENCRYPT 1 aes.h: # de ...
- const,static,extern 简介
const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...
- C++中的const
一,C++中const的基本知识 1.C++中const的基本概念 1.const是定义常量的关键字,表示只读,不可以修改. 2.const在定义常量的时候必须要初始化,否则报错,因为常量无法修改,只 ...
- const extern static 终极指南
const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...
- const let,console.log('a',a)跟console.log('a'+a)的区别
const 创建一个只读的常量 let块级作用域 const let重复赋值都会报错 console.log('a',a) a console.log('a'+a) a2 逗号的值会有空格:用加号的值 ...
- es6之let和const
在javascript中,我们都知道使用var来声明变量.javascript是函数级作用域,函数内可以访问函数外的变量,函数外不能访问函数内的变量. 函数级作用域会导致一些问题就是某些代码块内的变量 ...
- construction const parameter问题 构造函数const引用参数问题
工程在window下编译没有任何问题, 但是在linux(CentOS6)下编译就老是报错 C++ 编译器已升级到最新版 6.1.0 错误如下: In file included /bits/stl_ ...
- Error:const char* 类型的实参和LPCWSTR类型的形参不兼容的解决方法。
在C++的Windows 应用程序中经常碰到这种情况. 解决方法: 加入如下转换函数: LPCWSTR stringToLPCWSTR(std::string orig) { size_t origs ...
- C#基础知识七之const和readonly关键字
前言 不知道大家对const和readonly关键字两者的区别了解多少,如果你也不是很清楚的话,那就一起来探讨吧!探讨之前我们先来了解静态常量和动态常量. 静态常量 所谓静态常量就是在编译期间会对变量 ...
- const 与 readonly知多少
原文地址: http://www.cnblogs.com/royenhome/archive/2010/05/22/1741592.html 尽管你写了很多年的C#的代码,但是可能当别人问到你cons ...
随机推荐
- ios 动态修改UILabel字体大小
- (IBAction)sliderChange:(id)sender { NSLog(@"sliderChange"); UISlider *slider = (UISl ...
- (原)Windows下编译指纹识别的Rel_4.1.0库
网址:http://www.cnblogs.com/darkknightzh/p/4867372.html.未经允许,严禁转载. 没怎么用过linux,对于MSYS和MinGW也基本没用过,因而编译R ...
- 自己做jQuery插件:将audio5js封装成jQuery语音播放插件
日前的一个项目需要用到语音播放功能.发现Audio5js符合需求且使用简单,又鉴于jQuery控件便于开发操作,于是有了以下的封装. 首先先简单介绍一下Audio5js吧. Audio5js是一个能够 ...
- javascript事件捕获与冒泡
对“捕获”和“冒泡”这两个概念,我想我们对冒泡更熟悉一些,因为在我们使用的所有浏览器中,都支持事件冒泡,即事件由子元素向祖先元素传播的,就 像气泡从水底向水面上浮一样.而在像firefox,chrom ...
- [C++程序设计]函数模板
定义函数模板的一般形 式为 template < typename T> 或 template <class T> 函数模板: 函数参数个数,函数体相同.参数类型不同 函数重载 ...
- Onthink_项目后总结
---------------------------------------写代码不孤独__小小代(http://www.cnblogs.com/xiaoxiaodai/) 经过一段时间的沉寂,项目 ...
- JavaScript事件处理
客户端javascript程序采用了异步事件驱动程序,在这种程序设计风格下,当文档,浏览器,元素,或与之相关的对象发生某些有趣的事件时,web浏览器就会产生事件.事件本身不是javascript对象. ...
- Windows7里的“计算器”你真的会用吗?
“计算器”是不同Windows版本中的必备工具,虽然功能单一,但的确是人们日常工作中不可缺少的辅助工具,本文就来谈谈它的使用. 一.标准型和科学型两种面板 我们既可从Windows附件菜单中启动它,也 ...
- RESTful 架构
越来越多的人开始意识到,网站即软件,而且是一种新型的软件. 这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency).高 ...
- C# Process类_进程_应用程序域与上下文之间的关系
进程(Process)是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.进程之间是相对独立的,一个进程无法直接访问另一个进程的数据(除非分布式),一个进程运行的失败也不会影响其他 ...