const_cast
说明
const_cast 是类型转换运算符之一。 它用于更改任何对象的常量值,或者我们可以说它用于删除任何对象的常量性质。
函数指针和成员函数指针不可用于const_cast
[^1]
- 在任何程序中,const_cast 可用于将常量数据传递给另一个不接受常量数据的函数
#include <iostream>
using namespace std;
int change(int* p2) {
return (*p2 * 10);
}
int main() {
const int num = 100;
const int *p = #
int *p1 = const_cast <int *>(p);
cout << change(p1);
return 0;
}
// expre_const_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class CCTest {
public:
void setNumber( int );
void printNumber() const;
private:
int number;
};
void CCTest::setNumber( int num ) { number = num; }
void CCTest::printNumber() const {
cout << "\nBefore: " << number;
const_cast< CCTest * >( this )->number--;
cout << "\nAfter: " << number;
}
int main() {
CCTest X;
X.setNumber( 8 );
X.printNumber();
}
测试代码
#include <iostream>
using namespace std;
struct type {
int i;
type() : i(3) {}
void f(int v) const {
// this->i = v; // 编译错误:this 是指向 const 的指针
const_cast<type *>(this)->i = v; // 只要该对象不是 const 就 OK
}
};
const std::string &shortString(const std::string &s1, const std::string &s2) { return s1.size() < s2.size() ? s2 : s1; }
std::string &shortString(std::string &s1, std::string &s2) {
auto &s3 = shortString(const_cast<const string &>(s1), const_cast<const string &>(s2));
return const_cast<string &>(s3);
}
void ConstTest1() {
const int a = 1; ///>const int *
int *p;
p = const_cast<int *>(&a); ///>只能强转为int*
(*p)++;
// 1.编译错误:invalid use of const_cast with type ‘int’, which is not a pointer, reference, nor a
// pointer-to-data-member type
// int b = const_cast<int>(a);
// 2. 编译错误: invalid const_cast from type ‘const int*’ to type ‘char*’
// char *c = const_cast<char *>(&a);
// 3. 编译错误: invalid static_cast from type ‘const int*’ to type ‘char*’
// char *d = static_cast<char *>(&a);
std::cout << a << std::endl;
std::cout << *p << a << std::endl;
}
void ConstTest2() {
int i = 3;
const int a = i; ///>const int *
int &r = const_cast<int &>(a);
int &dd = r;
dd++;
std::cout << a << i << std::endl;
}
void ConstTest3() {
const char *pp;
char *p = const_cast<char *>(pp);
// 1. 编译错误: cannot convert ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ to ‘char*’ in
// initialization
// char *p1 = static_cast<std::string>(pp);
// 2. 编译错误: invalid conversion from ‘char’ to ‘char*’
// p = '1';
// 3. 运行时崩溃
// *p = '1';///>crash
}
void ConstTest4() {
const char pp = '2'; ///>const char*
// 1. 编译错误: invalid const_cast from type ‘const char*’ to type ‘int*
// char *p = const_cast<int *>(&pp);
char *p = const_cast<char *>(&pp);
*p += 1;
std::cout << "p " << p << std::endl;
*p++;
std::cout << "p " << p << std::endl;
}
void ConstTest5() {
//测试重载使用const_cast
std::string a = "123123";
std::string b = "123124141241";
std::cout << shortString(a, b) << std::endl;
}
void ConstTest6() {
int i = 3; // 不声明 i 为 const
const int &rci = i;
const_cast<int &>(rci) = 4; // OK:修改 i
std::cout << "i = " << i << '\n';
type t; // 假如这是 const type t,则 t.f(4) 会是未定义行为
t.f(4);
std::cout << "type::i = " << t.i << '\n';
const int j = 3; // 声明 j 为 const
int *pj = const_cast<int *>(&j);
// *pj = 4; // 未定义行为
void (type::*pmf)(int) const = &type::f; // 指向成员函数的指针
// const_cast<void(type::*)(int)>(pmf); // 编译错误:
}
int main() {
// const_cast只改变常量的属性
ConstTest1();
ConstTest2();
ConstTest3();
ConstTest4();
ConstTest5();
ConstTest6();
return -1;
}
1
21
43
p 3�i���
p �i���
123124141241
i = 4
type::i = 4
static_cast
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast
注:顶层const是指指针本身是个常量(int i=1;int * const fck=&i;
),底层const是指指针所指对象是个常量(const int i=1;const int *fck=&i;
);
虽然我们不能隐式得将一个左值转换为右值,但是我们可以使用static_cast显示的将一个左值转换为右值。
static_cast 也能用来进行向下转型,它不会有运行时检查的开销,但只有在程序(通过某些其他逻辑)能够保证 表达式 所指向的对象肯定是 Derived 时才是安全的。
dynamic_cast
RTTI(运行时类别检查)的功能由dynamic_cast
和typeid
两个运算符组成
dynamic_cast
运算符主要用于将基类的指针或引用安全地转换成派生类的指针或引用(沿继承层次结构向上、向下和横向安全地转换指向类的指针和引用)。
dynamic_cast
的使用形式如下:
//type必须是一个类 类型
dynamic_cast<type*>(e);///>e 必须是一个有效指针
dynamic_cast<type&>(e);///>e 必须是一个左值
dynamic_cast<type&&>(e);///>e 不能是左值
- 转换成功的条件为:
- e的类型是目标类型type的公有派生类
- e的类型是目标类型type的公有基类
- e的类型是目标类型type的类型
- 转换失败的代价:
- 若转换的目标type是指针类型,结果为0
- 若转换的目标type是引用类型,抛bad_cast异常(不存在所谓的空引用)。
- 指针类型的转换
#include <iostream>
#include <memory>
using namespace std;
struct Base
{
virtual ~Base() {}
};
struct Derived: Base
{
virtual void name() {cout<<"Derived"<<endl;}
};
int main()
{
//----------------------------------ok yo
Base *p = new Derived();
if(Derived*p1=dynamic_cast<Derived*>(p)){
cout<<"ok yo"<<endl;
}else{
cout<<"no no no yo"<<endl;
}
//----------------------------------no no no yo
Base *p1 = new Base();
if(Derived*p2=dynamic_cast<Derived*>(p1)){
p2->name();
cout<<"ok yo"<<endl;
}else{
cout<<"no no no yo"<<endl;
}
//----------------------------------ok yo"
Derived *p3 = new Derived();
if(Base*p4=dynamic_cast<Derived*>(p3)){
cout<<"ok yo"<<endl;
}else{
cout<<"no no no yo"<<endl;
}
return 0;
}
- 引用类型转换
#include <iostream>
#include <memory>
using namespace std;
struct Base
{
virtual ~Base() {}
};
struct Derived: Base
{
virtual void name() {cout<<"Derived"<<endl;}
};
int main()
{
Base b;
Base &p1=b;
//----------------------------------------ok
try{
Base & p2 = dynamic_cast< Base &>(p1);
cout<<"OK "<<endl;
}catch(bad_cast){
cout<<"bad cast"<<endl;
}
//----------------------------------------bad cast
try{
Derived & p3 = dynamic_cast< Derived &>(p1);
cout<<"OK "<<endl;
}catch(bad_cast){
cout<<"bad cast"<<endl;
}
return 0;
}
#include <iostream>
struct V
{
virtual void f() {} // 必须为多态以使用运行时检查的 dynamic_cast
};
struct A : virtual V {};
struct B : virtual V
{
B(V* v, A* a)
{
// 构造中转型(见后述 D 的构造函数中的调用)
dynamic_cast<B*>(v); // 良好定义:v 有类型 V*,V 是 B 的基类,产生 B*
dynamic_cast<B*>(a); // 未定义行为:a 有类型 A*,A 不是 B 的基类
}
};
struct D : A, B
{
D() : B(static_cast<A*>(this), this) {}
};
int main()
{
D d; // 最终派生对象
A& a = d; // 向上转型,可以用 dynamic_cast,但不是必须的
D& new_d = dynamic_cast<D&>(a); // 向下转型
B& new_b = dynamic_cast<B&>(a); // 侧向转型
}