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的一些总结的更多相关文章

  1. 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 ...

  2. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  3. C++中的const

    一,C++中const的基本知识 1.C++中const的基本概念 1.const是定义常量的关键字,表示只读,不可以修改. 2.const在定义常量的时候必须要初始化,否则报错,因为常量无法修改,只 ...

  4. const extern static 终极指南

    const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...

  5. const let,console.log('a',a)跟console.log('a'+a)的区别

    const 创建一个只读的常量 let块级作用域 const let重复赋值都会报错 console.log('a',a) a console.log('a'+a) a2 逗号的值会有空格:用加号的值 ...

  6. es6之let和const

    在javascript中,我们都知道使用var来声明变量.javascript是函数级作用域,函数内可以访问函数外的变量,函数外不能访问函数内的变量. 函数级作用域会导致一些问题就是某些代码块内的变量 ...

  7. construction const parameter问题 构造函数const引用参数问题

    工程在window下编译没有任何问题, 但是在linux(CentOS6)下编译就老是报错 C++ 编译器已升级到最新版 6.1.0 错误如下: In file included /bits/stl_ ...

  8. Error:const char* 类型的实参和LPCWSTR类型的形参不兼容的解决方法。

    在C++的Windows 应用程序中经常碰到这种情况. 解决方法: 加入如下转换函数: LPCWSTR stringToLPCWSTR(std::string orig) { size_t origs ...

  9. C#基础知识七之const和readonly关键字

    前言 不知道大家对const和readonly关键字两者的区别了解多少,如果你也不是很清楚的话,那就一起来探讨吧!探讨之前我们先来了解静态常量和动态常量. 静态常量 所谓静态常量就是在编译期间会对变量 ...

  10. const 与 readonly知多少

    原文地址: http://www.cnblogs.com/royenhome/archive/2010/05/22/1741592.html 尽管你写了很多年的C#的代码,但是可能当别人问到你cons ...

随机推荐

  1. tomact虚拟目录,虚拟主机,http请求头,相应头

    tomact虚拟目录,虚拟主机,http请求头,相应头 07. 五 / J2EE / 没有评论   一.服务器,容器(软件)1.服务器:提供网络访问的程序2.容器:支持什么技术的服务器就叫做什么容器. ...

  2. 变形课(DFS hdu 1181)

    变形课 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submis ...

  3. centos 6.5 安装 nginx+php+mysql

    一.准备工作 (1)配置防火墙 1.首先检查iptables服务的状态 [root@woxplife ~]# service iptables status iptables: Firewall is ...

  4. VS2010下WPF开发ARCGIS ENGINE 10的带Ribbon控件项目

    原文 http://blog.sina.com.cn/s/blog_47522f7f0100nq5t.html 题目好长,但是集目前最新的工具于一身..VS是最新的2010版,不过用的是.net3.5 ...

  5. jdk8预览

    原文:http://www.techempower.com/blog/2013/03/26/everything-about-java-8/ 1.接口增强 (1)接口可以定义static方法 java ...

  6. perl 创建文本框

    my $mw = MainWindow->new(-title => "Mem monitor"); $frm_name1 = $mw -> Frame()-&g ...

  7. Unique Binary Search Trees 解答

    Question Given n, how many structurally unique BST's (binary search trees) that store values 1...n? ...

  8. 正则表达式小试牛刀--匹配我的csdn博文标题

    正则表达式小试牛刀--匹配我的博文标题 作者:vpoet 邮箱:vpoet_sir@163.com 正则匹配,我以我的博客页面的博客标题为例:http://blog.csdn.net/u0130187 ...

  9. tangible T4 Editor 2.2.3 plus modeling tools for VS 2012 扩展名

    tangible T4 Editor 2.2.3 plus modeling tools for VS 2012 扩展名 tangible T4 Editor 2.2.3 plus modeling ...

  10. 二十六、Jcreator使用初步

    摘自http://blog.csdn.net/liujun13579/article/details/7751464 二十六.Jcreator使用初步 Jcreator是一个小巧灵活的Java开发工具 ...