C++之const在类用法小结
const指针指向问题
例1:
int main()
{
const int a=10;
//int *p=&a;//因为a是个const常量,而指针p可以改变a的值,相互矛盾
const int *s=&a;
//int *const p1=&a;//error 原因同上
const int *const p2=&a;
int b=10,c=20;
int *p=&b;
int *q=p;
*q=100;//q改变的是b的值,
q=&c;//q的改变不会影响p
return 0;
}
例2:
void fun(int *s)
{
*s=100;
cout<<*s<<endl;//100
s=new int (200);//这里s重新指向了一个堆区,并不影响p
}
int main()
{
int a=10;
int *p=&a;
fun(p);
cout<<*p<<endl;//100
return 0;
}
例3:
int a=10,b=20;
//const int *s=&a; //p1,p3错误
int *const s=&a;//p1,p2,p3,p4都正确,因为他们的改变不会影响s
//const int *const s=&a; //p1,p3错误
int *p1=s;
const int *p2=s;
int *const p3=s;
const int *const p4=s;
例4:
指针引用
int a=10,b=20;
int *s=&a;
int *&p=s;//s是指针的引用,所以s的改变会影响p
const int * &p1=s;//VC6.0上是对的,2012中是错的
int const * &p2=s;//VC6.0上是对的,2012中是错的
int * const &p3=s;//不允许通过改变p3的值去改变s
int * &const p4=s; //vc和2012都有警告
const int *const &p5=s;
const int *&const p6=s;//VC6.0上是对的,2012中是错的 //vc和2012都有警告
const int *const &const p7=s;//vc和2012都有警告
int a=10,b=20;
int *const s=&a;
// int *&p=s;//error
// const int * &p1=s;//error
// int const * &p2=s;//error
int * const &p3=s;
// int * &const p4=s; //error
const int *const &p5=s;
// const int *&const p6=s;//error
const int *const &const p7=s;
类1
class Test
{
private:
int value;
public:
Test(int x=0):value(x) {}
Test(const Test &it):value(it.value) {}
Test & operator=(const Test &it)
{
if(this != &it)
{
value = it.value;
}
return *this;
}
~Test() {}
public:
int GetValue() { return value;}//产生临时变量以寄存器返回,常性,不允许取地址
int GetValue() const { return value;}
int & GetRef() { return value;}//以引用返回,不产生临时变量
const int & GetRef() const { return value;}
//Value为常性,但以引用返回时可能通过变量改变value的值,故此函数前应加const
int * GetPtr() { return &value;}//将临时指针变量放在寄存器中返回,具常性,即指向不改变,不允许取地址
const int * GetPtr() const { return &value;}
};
实例1:
void main()
{
Test t1(10);
const Test t2(20);
int a1 = t1.GetValue();//Y
//int &b1 = t1.GetValue();//N:int tmp = t1.GetValue();tmp为常性
const int &c1 = t1.GetValue();//Y
//int tmp = t1.GetValue();const int &c1 = tmp;
// int *p1= &t1.GetValue();//N 临时变量的值存在寄存器中,不允许取寄存器的地址
int (Test:: *pfn)();
pfn = &Test::GetValue;
pfn = t1.GetValue;
int a2 = t2.GetValue();//Y
//int &b2 = t2.GetValue();//N
const int &c2 = t2.GetValue();//Y
//int *p2 = &t2.GetValue();//N
}
实例2:
void main()
{
Test t1(10);
const Test t2(20);
int a1 = t1.GetRef();//Y
int &b1 = t1.GetRef();//Y
const int &c1 = t1.GetRef();//Y
int *p1 = &t1.GetRef();//Y
int a2 = t2.GetRef();//Y
//int &b2 = t2.GetRef();//N value为const,引用需为const
const int &c2 = t2.GetRef();//Y
//const int *p2 = &t2.GetRef();//N
}
实例3
void main()
{
Test t1(10);
const Test t2(20);
int *a1 = t1.GetPtr();
//int *&b1 = t1.GetPtr();//返回值为常性
int *const &c1 = t1.GetPtr();
//const int **p1 = &t1.GetPtr();//不能对寄存器取地址
// int *a2 = t2.GetPtr();//可能通过改变地址改变value的值
const int *a2 = t2.GetPtr();
// int *&b2 = t2.GetPtr();
const int *const &c2 = t2.GetPtr();
// const int **p2 = &t2.GetPtr();
}
实例4
void main()
{
int a=10,b=20;
const int *const s = &a;//s指向a的地址,不允许通过s改变a,也不允许s指向别人
// int *&p = s;//指针引用,可以通过p改变s的指向
// const int *&p1 = s;
// int const *&p2 = s;
// int * const &p3 = s;
// int * & const p4 = s;
const int * const &p5 = s;
// const int * & const p6 = s;
}
实例5
class Test
{
int *ptr;
int ar[5];
public:
Test(int x=0):ptr(new int(x))
{
for(int i = 0;i<5;++i)
{
ar[i] = i;
}
}
~Test() { delete ptr;}
void fun1()
{
*ptr = 100;
delete ptr;//删除堆区的new区域,编译可通过
ptr = new int(200);
ar[2]=100;
}
void fun2() const
{
*ptr = 100;//ptr自身指向不变,指向空间的值改变,编译可通过
// delete ptr;
// ptr = new int(200);//ptr的指向改变,编译不能通过
//ar[2]=200;ar[2]自身改变了,编译不能通过
}
};
void main()
{
Test t1(10);
const Test t2(20);//指向不允许改变,指向地址的值可以改变
t1.fun1();
t1.fun2();
// t2.fun1();//常对象只能访问常方法
t2.fun2();
}
类2
class Test
{
private:
int *ptr;
public:
Test(int x=0):ptr(new int(x)) {}
~Test() { delete ptr;}
public:
int GetValue() { return *ptr;}//构建的临时对象在寄存器中,常性,不可取地址
int GetValue() const { return *ptr;}
int & GetRef() { return *ptr;}//通过引用返回ptr指向的值,不产生临时变量
int & GetRef() const { return *ptr;}
const int &GetRef2()const{return *ptr;}
int * GetPtr() { return ptr;}
int * GetPtr() const { return ptr;}
int *& GetRPtr() { return ptr;}//
int *const & GetRPtr() const { return ptr;}
int ** GetPPtr() { return &ptr;}
int *const * GetPPtr() const { return &ptr;}
};
若为const对象,则ptr指向不允许改变,指向地址的值可变
实例1
int GetValue() { return *ptr;}//返回ptr指向的值,构建的临时对象在寄存器中,常性,不可取地址
int GetValue() const { return *ptr;}
void main()
{
Test t1(10);
const Test t2(20);
int a1 = t1.GetValue();
//int &b1 = t1.GetValue();//临时变量为常性,不可通过引用改变它的值
const int &c1 = t1.GetValue();
//int *p1 = &t1.GetValue();//构建的临时对象在寄存器中,不可取地址
int a2 = t2.GetValue();
// int &b2 = t2.GetValue();
const int &c2 = t2.GetValue();
// int *p2 = &t2.GetValue();
}
实例2
int & GetRef() { return *ptr;}//通过引用返回ptr指向的值,不产生临时变量
int & GetRef() const { return *ptr;}//ptr指向不可变,指向的值可变
const int & GetRef1() const { return *ptr;}//ptr指向不可变,指向的值不可变
void main()
{
Test t1(10);
const Test t2(20);
int a1 = t1.GetRef();
int &b1 = t1.GetRef();
const int &c1 = t1.GetRef();
int *p1 = &t1.GetRef();
int a2 = t2.GetRef();
int &b2 = t2.GetRef();//允许通过改变引用来改变Ptr指向的值
const int &c2 = t2.GetRef();
int *p2 = &t2.GetRef();
int a3=t2.GetRef1();
// int &b3=t2.GetRef1();//
const int &c3=t2.GetRef1();
// int *p3=&t2.GetRef2();//
const int *p3=&t2.GetRef1();
}
实例3
int * GetPtr() { return ptr;}//以寄存器返回指向ptr指向的值的指针变量,常性,不可取地址
int * GetPtr() const { return ptr;}//ptr指向不可变,指向的值可变
const int *GetPtr1()const{return ptr;}//ptr指向不可变,指向的值不可变
void main()
{
Test t1(10);
const Test t2(20);
int *a1 = t1.GetPtr();
//int *&b1 = t1.GetPtr();//临时指针变量为常性
int *const &c1 = t1.GetPtr();
//int **p1 = &t1.GetPtr();//不可对寄存器取地址
int *a2 = t2.GetPtr();
// int *&b2 = t2.GetPtr();
int *const &c2 = t2.GetPtr();
// int **p2 = &t2.GetPtr();
// int *a3 =t2.GetPtr1();
const int *a3=t2.GetPtr1();
// int *&b3 =t2.GetPtr1();
const int *const &b3=t2.GetPtr1();
// const int *&c3=t2.GetPtr1();
const int *const &c3=t2.GetPtr1();
}
实例4
int *& GetRPtr() { return ptr;}//返回ptr
int *const & GetRPtr() const { return ptr;}//ptr为常性,则不允许通过引用改变它值,即它的指向
const int *const&GetRPtr1()const{return ptr;}
Test t1(10);
const Test t2(20);
int *a1 =t1.GetRPtr();
int *&b1 =t1.GetRPtr();
const int *&c1=t1.GetRPtr();//
int **p1 =&t1.GetRPtr();
int *a2 =t2.GetRPtr();
// int *&b2 =t2.GetRPtr();//error
int *const &b2=t2.GetRPtr();
// const int *&c2=t2.GetRPtr();
const int *const&c2=t2.GetRPtr();
// int **p2 =&t2.GetRPtr();//error
int *const*p2 =&t2.GetRPtr();
// int *a3 =t2.GetRPtr1();//error
const int *a3 =t2.GetRPtr1();
// int *&b3 =t2.GetRPtr1();//error
const int *const &b3 =t2.GetRPtr();
// const int *&c3 =t2.GetRPtr1();//error
const int *const &c3 =t2.GetRPtr();
// int **p3 =&t2.GetRPtr1();//error
const int *const*p3 =&t2.GetRPtr();
实例5
int ** GetPPtr() { return &ptr;}//以寄存器中的临时地址变量返回
int *const * GetPPtr() const { return &ptr;}
const int *const * GetPPtr() const { return &ptr;}
Test t1(10);
const Test t2(20);
int **a1 =t1.GetPPtr();
// int **&b1=t1.GetPPtr();
int **const&b1=t1.GetPPtr();
// const int **&c1=t1.GetPPtr();//error
int *const*const&c1=t1.GetPPtr();
// int ***p1 =&t1.GetPPtr();//无法对寄存器取地址
int *const*a2 =t2.GetPPtr();
int *const*const&b2 =t2.GetPPtr();//
int *const*const&c2=t2.GetPPtr();//
// int ***p2 =&t2.GetPPtr();//
const int *const *a3 =t2.GetPPtr1();//
const int *const *const &b3 =t2.GetPPtr1();//
const int *const* const&c3=t2.GetPPtr1();//
//int***p=&t2.GetPPtr1();//
类3
class Int
{
private:
int num;
public:
Int(int x = 0):num(x) { cout<<"Create Int: "<<this<<endl;}
Int(const Int &it):num(it.num) {cout<<"Copy Create Int: "<<this<<endl;}
Int & operator=(const Int &it)
{
if(this != &it)
{
num = it.num;
}
cout<<" = "<<endl;
return *this;
}
~Int() {cout<<"Destroy Int: "<<this<<endl;}
};
class Test
{
Int value;
public:
Test(const Int &x):value(x) {}
~Test() {}
public:
Int GetValue() { return value;}//返回构建于栈帧的临时对象,不具有常性,地址可取
Int GetValue() const { return value;}
Int & GetRef() { return value;}//返回构建于栈帧的value的引用
const Int & GetRef() const { return value;}
Int * GetPtr() { return &value;}//返回指向value的临时指针变量,自定义类型,不具常性
const Int * GetPtr() const { return &value;}
};
实例1
Int GetValue() { return value;}//返回构建于栈帧的临时对象,不具有常性,地址可取
Int GetValue() const { return value;}
Int a = 10,b=20;
Test t1(a);
const Test t2(b);
Int a1 = t1.GetValue();
Int &b1 = t1.GetValue();
const Int &c1 = t1.GetValue();
Int *p1 = &t1.GetValue();//指针为弱引用,函数结束后析构
Int a2 = t2.GetValue();
Int &b2 = t2.GetValue();//引用临时对象,即使改变临时对象的值也不会改变value的值
const Int &c2 = t2.GetValue();
Int *p2 = &t2.GetValue();//
实例2
Int & GetRef() { return value;}//返回构建于栈帧的value的引用
const Int & GetRef() const { return value;}
Int a = 10,b=20;
Test t1(a);
const Test t2(b);
Int a1 = t1.GetRef();
Int &b1 = t1.GetRef();
const Int &c1 = t1.GetRef();
Int * p1 = &t1.GetRef();
Int a2 = t2.GetRef();
// Int &b2 = t2.GetRef();
const Int &c2 = t2.GetRef();
// Int *p2 = &t2.GetRef();
const Int *p2 = &t2.GetRef();
实例3
Int * GetPtr() { return &value;}//以寄存器返回指向value的临时指针变量,具有常性
const Int * GetPtr() const { return &value;}
Int a = 10,b=20;
Test t1(a);
const Test t2(b);
Int *a1 = t1.GetPtr();
// Int *&b1 = t1.GetPtr();
Int *const&c1 = t1.GetPtr();
// Int ** p1 = &t1.GetPtr();
// Int *a2 = t2.GetPtr();
const Int *a2 = t2.GetPtr();
// Int *&b2 = t2.GetPtr();
// const Int *&c2 = t2.GetPtr();
const Int *const &c2 = t2.GetPtr();
// Int **p2 = &t2.GetPtr();
总结:
1、内置类型:
a.以值返回:返回构建于寄存器中,使用此值拷贝构造的临时变量,具有常性,不可对其进行取地址操作
b.以引用返回:不产生临时变量,可对其进行取地址操作
c.以指针返回:以寄存器返回临时指针变量,具有常性,不可对其进行取地址操作
2、自定义类型:
a.以值返回:返回构建在栈帧的临时对象,可取地址,不具有常性
b.以引用返回:不产生临时变量,可对其进行取地址操作
c.以指针返回:以寄存器返回临时指针变量,具有常性,不可对其进行取地址操作
3.指针引用: