#include <iostream>
using namespace std;
class Test
{
public:
Test(int data = 10) :mptr(new int(data)) {}
~Test() {}
//1 返回整型值 ,内置类型的返回值通过寄存器带出。
int GetInt() { return *mptr; }
int GetInt()const { return *mptr; }
//2 返回引用 引用的变量是累作用域,出了这个函数,mptr依然存在,即返回的是*mptr本身
int& GetIntRef() { return *mptr; }
int& GetIntRef()const { return *mptr; }
//3 返回指针,指针类型与内置类型一样,都是值(立即数),通过eax带出,不能取地址
int* GetPtr() { return mptr; }
int* GetPtr()const { return mptr; }
//4 返回指针的引用 返回的是&mptr。
int*& GetPtrRef() { return mptr; }
int* const& GetPtrRef()const { return mptr; }// int* const *返回引用时,就是在给mptr隐式取地址
/*
返回值类型:int * const * 《==》 mptr类型:int * const *
引用的值ptr 1 已初始化
2 可以取地址
3 是常量 (int * const *)
返回的常引用 int * const &
*/
private:
int *mptr;
/*
在常成员方法中,const修饰的是mptr ,指针本身不能改变 。*mptr可以变。
*/
};
/*
一 检查类型是否匹配
二 是否使用引用
2.1 引用是否被初始化
2.2 引用的值能否取地址
2.3 引用的是否是一个常量
*/
int main4()
{
//4 返回指针的引用 返回的是&mptr。
//int*& GetPtrRef() { return mptr; }
//int* const& GetPtrRef()const { return mptr; }// int* const *
Test t1;
const Test t2;
int *a1 = t1.GetPtrRef(); // int * = int * 普通指针 接收 普通引用
int *&b1 = t1.GetPtrRef(); //int * = int * 普通引用 接收 普通引用
const int *&c1 = t1.GetPtrRef(); //应该改成 const int * const &c1 = t1.GetPtrRef(); //返回的是&mptr 地址也是立即数,需要用常引用接收
int *a2 = t2.GetPtrRef(); //???int * = int * 指针接收 不取地址。
int *&b2 = t2.GetPtrRef(); / 错误 。int* * != int * const* 类型不匹配
const int *&c2 = t2.GetPtrRef();// 错误 。const int* * != int * const* 类型不匹配
//c2(普通)引用一个 指向整型常量的 指针, 右值是一个常指针指向整型变量 的 引用
return 0;
}
int main3()
{
//3 返回指针,指针类型与内置类型一样,都是值(立即数),通过eax带出,不能取地址
//int* GetPtr() { return mptr; }
//int* GetPtr()const { return mptr; }
Test t1;
const Test t2;
int *a1 = t1.GetPtr(); //用mptr给a1初始化。a1指向 mptr指向的内存。
int *&b1 = t1.GetPtr(); ///错的 。b1是普通引用,不能接受立即数,无法取地址
const int *&c1 = t1.GetPtr();//错的 。 const修饰*c1,代表c1指向的是一个整型常量 ,c1本身是普通引用,不能接受 立即数
//int * const &d1 = t1.GetPtr(); const修饰引用,常引用 引用 常量
int *a2 = t2.GetPtr();//返回的类型是 int * , 类型匹配
int *&b2 = t2.GetPtr(); /返回指针,指针类型与内置类型一样,都是值(立即数),通过eax带出,不能取地址
const int *&c2 = t2.GetPtr();//同c1一样,c2是普通引用 ,不能引用常量
return 0;
}
int main2()
{
//2 返回引用 引用的变量是类作用域,出了这个函数,mptr依然存在,即返回的是*mptr本身 ,即mptr指向的内存。
//int& GetIntRef() { return *mptr; } //int *
//int& GetIntRef()const { return *mptr; } //int *
Test t1;
const Test t2;
int a1 = t1.GetIntRef();//类型匹配, int 接收 int ,相当于用返回值*mptr对a1进行初始化
int &b1 = t1.GetIntRef(); ///即b1是 *mptr的别名
const int &c1 = t1.GetIntRef(); // 常引用 接收一个 普通引用,代表不能通过c1改变*mptr
//不论是常方法还是普通方法 ,返回的都是值,与const无关。const 修饰的是指针mptr
//故以下结果一样
int a2 = t2.GetIntRef();
int &b2 = t2.GetIntRef(); /
const int &c2 = t2.GetIntRef();
return 0;
}
int main1()
{
//1 返回整型值 ,内置类型的返回值通过寄存器带出。
//int GetInt() { return *mptr; }
//int GetInt()const { return *mptr; }
Test t1;
const Test t2;
int a1 = t1.GetInt(); //调用普通方法
int &b1 = t1.GetInt(); //错误 。返回的值是通过寄存器带出,不能取地址,故需要常引用去引用 //int const &b1 = t1.GetInt();
const int &c1 = t1.GetInt();//用一个临时对象接收寄存器的值,然后对临时对象进行引用
//不论是常方法还是普通方法 ,返回的都是值,与const无关。const 修饰的是指针mptr
//故以下结果一样
int a2 = t2.GetInt(); //调用常方法
int &b2 = t2.GetInt(); //错误 。类型是匹配的 ,但是返回的值是通过寄存器带出,不能取地址,故需要常引用去引用
const int &c2 = t2.GetInt();//用一个临时对象接收寄存器的值,然后对临时对象进行引用
return 0;
}
/*
错误的类型转换
const int* => int*
const int** => int**
const int* => int*&
int** => const int**
int* => const int*&
int *const** => int***
int*** => int *const**
*/
总结:
Const
Const 修饰的常量 1 必须初始化 2不能做左值。
原因:常量在编译阶段,直接所用地方替换成值。
如果非要修改,可以在代码中嵌入汇编代码,进行修改。
Const 与 *
Const与一级指针结合,必须保证不能间接修改常量的值,常量的地址也不能泄露到不安全的人手里,这个不安全的人指普通指针 和普通引用。
Const 修饰指针才参与类型 ,
Const 修饰值 与类型无关 。
Const 与 &
Const与引用结合,使用引用时需要考虑三点:
l 引用是否初始化
l 引用的值是否可以取地址
l 引用的是否是常量,如果是常量需要用常引用。
因为常量在编译阶段已是值,不能取地址。立即数同理。
在汇编代码中,常引用即用一个临时变量保存常量的值,然后对这个临时变量进行引用。
Const 与**
Const与多级指针结合,少一个const 多一个const都不可以,类型必须完全匹配。