C/C++中的const分析

目录

C中的const

C++中的const

mutable关键字

const成员变量、函数、对象


C中的const

const只读变量

const修饰的变量是只读的,本质还是变量,const只在编译期有用,在运行期无用

const修饰的局部变量在栈上分配空间,const修饰的全局变量在全局数据区分配空间

const修饰的变量不是真的变量,它只是告诉编译器该变量不能出现在赋值符号的左边

const全局变量的分歧

现代C编译器中的const将具有全局生命周期变量存储于只读存储区,修改const全局变量将导致程序崩溃

标准C语言编译器不会将const修饰的全局变量存储于只读存储区(.rodata)中,而是存储于可修改的全局(静态)数据区(.bss 和 .data),其值依然可以改变

const不能定义真正意义上的常量!!!而enum的枚举值却可以

#include <stdio.h>  

const char* s = "wss";
const int g_cc = 2;

int main()
{
	const int cc = 1;

	int* p = (int*)&cc;

	printf("cc = %d\n", cc);

	*p = 3;

	printf("cc = %d\n", cc);

	p = (int*)&g_cc;

	printf("g_cc = %d\n", g_cc);

	*p = 4;

	printf("g_cc = %d\n", g_cc);

	return 0;
}

gcc:

 

BCC(标准C):

#include <stdio.h>  
  
const int g_array[5] = {0};    // 只读存储区(现)
  
void modify(int* p, int v)  
{  
    *p = v;  
}  
  
int main()  
{  
    int const i = 0;           // 栈
    const static int j = 0;    // 只读存储区
    int const array[5] = {0};  // 栈
      
    modify((int*)&i, 1);           // ok  
    modify((int*)&j, 2);           // error  
    modify((int*)&array[0], 3);    // ok  
    modify((int*)&g_array[0], 4);  // error  
      
    printf("i = %d\n", i);  
    printf("j = %d\n", j);  
    printf("array[0] = %d\n", array[0]);  
    printf("g_array[0] = %d\n", g_array[0]);  
      
    return 0;  
}  

BCC:

gcc:

        

const修饰函数参数和返回值

const修饰函数参数表示在函数体内不希望改变参数的值,const修饰函数返回值表示返回值不可改变,多用于返回指针的情形

C++中的const

C++对const的升级

C++在C的基础上对const进行了进化处理,当碰见const声明时在符号表中放入常量,编译过程中若发现使用常量则直接以符号表中的值替换,此时为真正意义上的常量

          

C语言中的const变量C语言中const变量是只读变量,会分配存储空间

C++中的const常量:C++编译器虽然可能会为const常量分配空间,但不会使用其存储空间的值 ,兼容C语言       

#include <stdio.h>  
  
int main()  
{  
    const int c = 0;  
    int* p = (int*)&c;  
      
    printf("Begin...\n");  
      
    *p = 5;  
      
    printf("c = %d\n", c); 
     
    printf("*p = %d\n", *p);
  
    printf("End...\n");  
      
    return 0;  
}  

gcc:

g++:

C++中的const常量与宏定义不同:const常量由编译器处理,编译器对const常量进行类型检查作用域检查,宏定义由预处理器处理,单纯的文本替换

#include <stdio.h>  
  
void f()  
{  
    #define a 3  
    const int b = 4;  
}  
  
void g()  
{  
    printf("a = %d\n", a);  
    //printf("b = %d\n", b);  //error: 'b' was not declared in this scope
}  
  
int main()  
{  
    const int A = 1;  
    const int B = 2;  
    int array[A + B] = {0};  
    int i = 0;  
      
    for(i=0; i<(A + B); i++)  
    {  
        printf("array[%d] = %d\n", i, array[i]);  
    }  
      
    f();  
    g();  
      
    return 0;  
}  

const常量的判别准则 

只有用字面量初始化的const常量才会进入符号表 ,使用其它变量初始化的const常量仍然是只读变量,被volatile修饰的const常量不会进入符号表 

注意:在编译期间不能直接确定初始值的const标识符,都被作为只读变量处理!!!

const引用的类型与初始化变量的类型 如果相同:初始化变量成为只读变量 ,如果不同:生成—个新的只读变量 

#include <stdio.h>  
  
int main()  
{  
    const int x = 1;   // 进入编译器符号表
    const int& rx = x; // 只读变量 
      
    int& nrx = const_cast<int&>(rx);  
      
    nrx = 5;   // 修改内存值    
      
    printf("x = %d\n", x);       // 1   编译器直接从符号表替换
    printf("rx = %d\n", rx);     // 5   从内存获值
    printf("nrx = %d\n", nrx);   // 5
    printf("&x = %p\n", &x);  
    printf("&rx = %p\n", &rx);  
    printf("&nrx = %p\n", &nrx); //  &x == &rx == &nrx
      
    volatile const int y = 2;       // 不会进入符号表
    int* p = const_cast<int*>(&y);  
      
    *p = 6;  
      
    printf("y = %d\n", y);  // 6
    printf("p = %p\n", p);  
      
    const int z = y;        // 只读变量
      
    p = const_cast<int*>(&z);  
      
    *p = 7;  
      
    printf("z = %d\n", z);  // 7
    printf("p = %p\n", p);  
      
    char c = 'c';  
    char& rc = c;  
    const int& trc = c;  // 类型不同,生成新的只读变量
      
    rc = 'a';            // 不会影响新的只读变量
      
    printf("c = %c\n", c);     // a
    printf("rc = %c\n", rc);   // a
    printf("trc = %c\n", trc); // c 
      
    return 0;  
}  

  

 

mutable关键字

目的:统计对象中某个成员变量的访问次数 

mutable是为了突破const函数的限制而设计的 ,mutable成员变量将永远处于可改变的状态 ,mutable在实际的项目开发中被严禁滥用

mutable成员变量破坏了只读对象的内部状态 ,const成员函数保证只读对象的状态不变性 ,mutable成员变量的出现无法保证状态不变性

#include <iostream>  
  
using namespace std;  
  
class Test  
{  
    int m_value;  
    mutable int m_count;  
public:  
    Test(int value = 0)  
    {  
        m_value = value;  
        m_count = 0;  
    }  
      
    int getValue() const  
    {  
        m_count++;  //const成员函数内部不能直接改变成员变量值,所以需要mutable关键字  
        return m_value;  
    }  
      
    void setValue(int value)  
    {  
        m_count++;   
        m_value = value;  
    }  
      
    int getCount() const  
    {  
        return m_count;   
    }  
  
};  
  
int main(int argc, char *argv[])  
{  
    Test t;  
      
    t.setValue(100);  
      
    cout << "t.m_value = " << t.getValue() << endl;  
    cout << "t.m_count = " << t.getCount() << endl;  
      
    const Test ct(200);  
      
    cout << "ct.m_value = " << ct.getValue() << endl;  
    cout << "ct.m_count = " << ct.getCount() << endl;  
      
    return 0;  
}  

下面是更好的解决方案(不用mutable)

#include <iostream>  
#include <string>  
  
using namespace std;  
  
class Test  
{  
    int m_value;  
    int * const m_pCount;  
    /* mutable int m_count; */  
public:  
    Test(int value = 0) : m_pCount(new int(0))  
    {  
        m_value = value;  
        /* m_count = 0; */  
    }  
      
    int getValue() const  
    {  
        /* m_count++; */    //只读对象内部不能直接改变  
        *m_pCount = *m_pCount + 1;  
        return m_value;  
    }  
      
    void setValue(int value)  
    {  
        /* m_count++; */  
        *m_pCount = *m_pCount + 1;  
        m_value = value;  
    }  
      
    int getCount() const  
    {  
        /* return m_count; */  
        return *m_pCount;  
    }  
  
    ~Test()  
    {  
        delete m_pCount;  
    }  
};  
  
int main(int argc, char *argv[])  
{  
    Test t;  
      
    t.setValue(100);  
      
    cout << "t.m_value = " << t.getValue() << endl;  
    cout << "t.m_count = " << t.getCount() << endl;  
      
    const Test ct(200);  
      
    cout << "ct.m_value = " << ct.getValue() << endl;  
    cout << "ct.m_count = " << ct.getCount() << endl;  
      
    return 0;  
}  

 

const成员变量、函数、对象

类中的const成员

类中的const成员会被分配空间的 ,类中的const成员的本质是只读变量 ,类中的const成员只能在初始化列表中指定初始值 (引用数据成员也是)

编译器无法直接得到const成员的初始值,因此无法进入符号表成为真正意义上的常量。

#include <stdio.h>  
  
class Value  
{  
private:  
    int mi;  
public:  
    Value(int i)  
    {  
        printf("i = %d\n", i);  
        mi = i;  
    }  
    int getI()  
    {  
        return mi;  
    }  
};  
  
class Test  
{  
private:  
    const int ci;  
    Value m2;  
    Value m3;  
    Value m1;  
public:  
    Test() : m1(1), m2(2), m3(3), ci(100)  
    {  
        printf("Test::Test()\n");  
    }  
    int getCI()  
    {  
        return ci;  
    }  
    int setCI(int v)  
    {  
        int* p = const_cast<int*>(&ci);  
          
        *p = v;  
    }  
};  
  
  
int main()  
{  
    Test t;  
      
    printf("t.ci = %d\n", t.getCI());  
      
    t.setCI(10);  
      
    printf("t.ci = %d\n", t.getCI());  
      
    return 0;  
}  

 

const对象

const关键字能够修饰对象 ,const修饰的对象为只读对象 ,只读对象的成员变量不允许被改变 ,只读对象是编译阶段的概念,运行时无效 

const成员函数

const对象只能调用const的成员函数 ,const成员函数中只能调用const成员函数 ,const成员函数中不能直接改写成员变量的值(使用mutable可以)

类中的函数声明与实际函数定义中都必须带const关键字。const成员函数的定义:Type ClassName::function(Type p) const 

#include <iostream>

using namespace std;

class Test
{
public:
    int ci;

    Test():ci(1){}

    int getCI() const//本质:const成员函数 ==> const Test* const this
    {
        return ci;
    }

    void print()
    {
        cout << "我是非const成员函数" << endl;
    }
};

int main()
{
    Test t;

    cout << t.getCI() << endl;//1

    const Test tt;

    cout << tt.getCI() << endl;//1
    //tt.print();//error: 'this' argument to member function 'print' has type 'const Test', but function is not marked const

    Test* ptt = const_cast<Test*>(&tt);

    ptt->ci = 0;
    cout << ptt->getCI() << endl;//0
    ptt->print();

    return 0;
}

 

                

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值