常量指针与指针常量
常量指针:指向常量的指针,const int p ;
指针常量:指针变量为常量,int * const p;
share_ptr < T > p;与T p类似,都是非常量
const share_ptr < T > p;与T* const p类似,指针p是常量
share_ptr < const T > p;与const T* p类似,p指向的内容是常量
const share_ptr < const T > p;与const T* const p类似,都是常量
#include <iostream>
#include <memory>
int main()
{
std::shared_ptr<int> A(new int(10)); //指针A以及A所指内容均为非常量
const std::shared_ptr<int> B(new int(20)); //指针B为常量,B所指内容均为非常量
std::shared_ptr<const int> C(new int(30)); //指针C为非常量,C所指内容为常量
const std::shared_ptr<const int> D(new int(40)); //指针D以及D所指内容均为常量
*A = 11;
std::cout << "*A:" << *A << std::endl;
A = B;
std::cout << "*A:" << *A << std::endl;
*B = 21;
std::cout << "*B:" << *B << std::endl;
//B = C; //编译器报错,指针B为常量
std::cout << "*B:" << *B << std::endl;
//*C = 31; //编译器报错,C所指内容为常量
std::cout << "*C:" << *C << std::endl;
C = D;
std::cout << "*C:" << *C << std::endl;
//*D = 41; //编译器报错,指针D为常量
std::cout << "*D:" << *D << std::endl;
//D = A; //编译器报错,D所指内容为常量
std::cout << "*D:" << *D << std::endl;
return 0;
}
强制类型转换
C++中新增了四个强制类型转换的关键字,分别为static_cast、const_cast、reinterpret_cast和dynamic_cast。
1、static_cast
用法:static_cast <类型说明符> (变量或表达式);它主要用于基本数据类型之间的转换、空指针转换成目标类型的空指针、任何类型的表达式转换为void类型以及类层次结构中基类和派生类之间指针或引用的转换,上行转换(把派生类的指针或引用转换成基类表示)是安全的,下行转换(把基类的指针或引用转换为派生类表示)没有动态类型检查,不安全。
2、const_cast
用法:const_cast<指针/引用> (变量或表达式);它主要用来修改类型的const或volatile属性,常量指针或引用被转换成非常量指针或引用,并且仍然指向原来的对象,常量对象被转换成非常量对象。
#include<iostream>
using namespace std;
int main()
{
int a = 10;
const int * p = &a;
int *q;
q = const_cast<int *>(p);
*q = 20; //fine
cout << " " << a << " " << *p << " " << *q << endl;
cout << " " << &a << " " << p << " " << q << endl;
cout << endl << endl;
return 0;
}
运行结果:
#include<iostream>
using namespace std;
int main()
{
const int a = 10;
const int * p = &a;
int *q;
q = const_cast<int *>(p);
*q = 20; //fine
cout << a << " " << *p << " " << *q << endl;
cout << &a << " " << p << " " << q << endl;
return 0;
}
运行结果:
对比运行结果可知,当a为非常量时,q指针将a的内容改为了20,但当a为常量时,“*q=20”语句为未定义行为语句,a的值还是为10。
3、reinterpret_cast
用法:reinterpret_cast<指针/引用> (变量或表达式);它主要用来改变指针或引用的类型、将指针或引用转换为一个足够长度的整形、将整型转换为指针或引用类型。
4、dynamic_cast
用法:dynamic_cast<指针或引用> (变量或表达式);以上三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL。使用dynamic_cast进行类转换时基类中一定要有虚函数,否则编译不通过,因为类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。对于类的转换,上行转换时dynamic_cast和static_cast的效果是一样的,下行转换时dynamic_cast具有类型检查的功能,比static_cast更安全。
#include<iostream>
using namespace std;
class base
{
public:
virtual void vfun() { cout <<"base::vfun" << endl; }
void fun() { cout << "base::fun" << endl; }
void b() { cout << "base" << endl; }
};
class derived : public base
{
public:
void vfun() { cout << "derived::vfun" << endl; } //重写(base类中vfun为虚函数)
void fun() { cout << "derived::fun" << endl; } //覆盖(base类中fun不为虚函数)
void d() { cout << "derived" << endl; }
};
int main()
{
base * instance_b;
instance_b = new derived;//编译成功,可以使用基类指针指向派生类,派生类重写
instance_b->vfun();
instance_b->fun();
instance_b->b();
cout << endl;
derived * instance_d;
//instance_d = new base;//编译报错,只能使用基类指针指向派生类,并不能派生类指针指向基类
//instance_d = static_cast<derived *>(new base); //不检测类型转换是否安全,基类可以没有虚函数
instance_d = dynamic_cast<derived *>(new base); //转换失败
if (instance_d == nullptr)
cout << "转换失败!" << endl;
else
{
instance_d->vfun();
instance_d->fun();
instance_d->b();
instance_d->d();
}
cout << endl;
instance_d = dynamic_cast<derived *>(instance_b); //运行时检测类型转换是否安全,基类必须存在虚函数
if (instance_d == nullptr)
cout << "转换失败!" << endl;
else
{
instance_d->vfun();
instance_d->fun();
instance_d->b();
instance_d->d();
}
delete instance_b;
return 0;
}
运行结果: