c++学习 4

本文详细探讨了C++中变量与常量的区别、const的作用机制,以及const修饰对象和指针的区别。还讲解了引用的概念,内存模型比较,以及指针与引用的差异和限制。
摘要由CSDN通过智能技术生成

1. 变量 vs 常量

  • 常量: 在编译时会被存储在内存表中的一个实体。

  • 变量: 编译器为其分配内存,地址。
    进程的内存映像

  • 全局常量波通常会被分配在只读代码/数据区。(从地址来看,发现s1的地址与main的地址非常相近,说明全局常量被分配在代码段里)

#include<stdio.h>
int main(void)
{
     char *s1="Hello world";   //“Hello world” 全局常量,分配在代码段里,
     						   //这里的“=”只是简单的将地址赋值给s1
     //s1[0]='A'; error
     char s2[]="Hello world";  //“=”拷贝,将代码段里的“Hello world” 拷贝到堆栈中
    						   //然后将址赋值给s2
     //s2[0]=‘A’; correct
     printf("main: %p\n",main); //main: 0401550
     printf("s1:  %p\n", s1);   //s0:   0404000
     printf("s2:  %p\n",s2);    //s1:   061FE0c
}
  • const 在编译时刻必须被知道,因此必须被初始化。编译器保证const 值不会被修改。计算机访问内存地址时,mmu负责翻译为物理地址并进行内存保护,从而保证const值不被修改。

2. const 修饰对象vs 指针

  • const 修饰指的是不能通过变量去修改,而不是指的是那块内存本身是不是const 。
  • *const A p: 对象是const. 即 *p 不能做左值。A * const p : 指针是const.即p 不能做左值。const 在 * 前,对象是const.const 在 * 后 ,指针是const.
  • 【1】 int A::f() const{} 即是对象里的成员变量不可修改 <====> int A::f(const A* this)
    【2】 int A:: f() {};
    A::f()const与A::f() 构成重载(函数名相同,但形参个数或类型不同)
class A
{
public:
   A(/* args */){};
   ~A(){};
   void f(){ cout<<"A::f()"<<endl;};
   void f() const{cout<<"A::f()const"<<endl;}
};

int main(){
   A a;
   const A b;
   a.f();   // 调用的A::f() ,因此打印  “A::f()”;
   b.f();   // 调用的A::f() const 因此打印 “A::f()const”
   return 0;
}
const int c=3;
int *p= &c;  //错误了,因为通过*p可以修改c,打破了ci是const的限制

3. const 修饰类成员变量

  • 成员变量时const,因为无法修改const,所以必须被初始化,不能做数组的size.这是因为在C++中,类的成员变量必须在编译时就确定大小。在这个例子中,数组s的大小是由const成员变量size来确定的,而const成员变量size的值是在运行时才确定的。这样的定义是错误的,因为数组的大小必须在编译时就确定。
class A{
    const int  size;
    int s[size];   // ERROR
};
  • 类的内存映像
    类的内存映像
class A{
    public: 
    const int  size;
    int s[10];
    public:
    A(int s);
};

A::A(int s):size(5){
    cout<<"A::A()"<<endl;
}

int main(){
    A a(11);
    printf("&a:      %p\n",&a);             //输出&a: 061fdf0
    printf("&a.size: %p",&a.size);          //输出&a.size: 061fdf0
    printf("a.s: %p",&a.s);                 //输出a.s:  061fdf4
    return 0;
}

3. const 修饰形参

  • void f(const int * x) 形参是指针,编译器会保证不能通过 指针修改x所指的变量的值。
  • 传值会在堆栈分配空间,尤其是传对象时会耗费很多的内存空间。传地址时,在对象前加const,可以办证函数不会修改对象的成员变量。

4. 引用

  • 引用实际上就是变量的别名
char &r=c;  //r即c的别名
  • 初始化:定义时绑定变量,绑定后,不能再绑定其它对象
  • 赋值: 将值赋值给其所绑定的变量
    int x = 3;
    int y = 5;
    int &a = x;
    int &b = y;
    a = b; // 将b所绑定的变量的值的赋值给a 所绑定变量的值
    cout << "a=" << a << endl;  //a=5
    cout << "b=" << b << endl;  //b=5
  • 规则: 【1】本地变量定义时一定要初始化,在运行时绑定的对象不变【2】 函数调用,成员变量,绑定在函数调用和成员遍量初始化时进行。
  • g(a); 不能相信在函数调用后a的值不会发生变化(函数原型为 void g(int &a),有可能在函数内部堆a进行修改)
int& h(){
	int q=0;
	return q;//错误,因为函数调用之后局部变量会被销毁,导致引用悬空
}
  • 实质上就是const 指针(A *const p),让代码少些 *、
  • const int &z=x; z是x的别名,但通过z不能修改x的值,,即z不能做左值。

4. c++ vs java 内存模型

  • c++内存模型
    c++ 内存模型
  • java内存模型
    Java内存模型
    java中引用的其实等同于c++的指针,因为引用绑定的对象在运行时不可更改。外形没有* ,不能做指针的计算 .而c的指针可以进行计算。
A a=new a();
B b=new b();
a=b; //将a所指的指针指向b所指的对象

5.指针 vs 引用

指针vs引用

void f(int &b);
int main(){
	f(6);//ERROR,因为临时变量没有名字。绑定智能绑定已存在的变量。
}

6. 引用限制

//int & *p; *p的类型是refernece,如果 *p是reference,则指可以取到reference的地址,而reference 的地址是不可取到的。
 //int * &p; p是reference ,但捆着的变量是int 指针。
  • 不能创建引用数组,因为引用不是对象,不能被声明为一个数组。
int x = 10;  
int& refs[3] = {x, x, x};  // 错误:不能创建引用数组
  • 24
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值