[C/C++]_[中级]_[static_cast的详细解析]
Posted infoworld
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C/C++]_[中级]_[static_cast的详细解析]相关的知识,希望对你有一定的参考价值。
场景
- 在
C++
开发时,会看到四个强制类型转换操作符const_cast
,dynamic_cast
,static_cast
和reinterpret_cast
。其中static_cast
的用在什么场景下?
说明
static_cast
是不安全的转换,不会对类型进行检查。只在一种情况下进行简单检查,即没有继承关系的对象不能转,编译报错。通常用在把指向基类的指针转换为指向子类的指针;可以用在数值类型int
,char
,enum
,float
,double
等之间的转换;一般用在非多态(无virtual
)的类型转换中。
static_cast <type-id> ( expression )
基类向下转换
type-id
可以是引用类型,指针类型。
D& d2 = static_cast<D&>(b2);
D* d2_3 = dynamic_cast<D*>(&b2);
- 对实际类型是父类型的对象转换为子类型,可以转,但是调用时结果是未定义的。也就可能运行时报错,也可能不报错。
dynamc_cast
动态转换失败会返回0
,而0
初始化一个引用类型D&
会崩溃, 如果是转换为dynamic_cast<D*>
就不会报错。
B b2;
D& d2 = static_cast<D&>(b2);
//因为dynamc_cast动态转换失败会返回0,而0初始化一个引用类型D&会崩溃。
//D& d2_2 = dynamic_cast<D&>(b2);
左值(lvalue)转换为过期值(xvalue)
- 左值
lvalue
转换为过期值xvalue
,items
已经失效,size
是0
.有时候需要某些元素添加更长的生命周期,转换为xvalue
是最小的代价。
vector<int> items = 1,2,3;
vector<int>* items2 = new vector<int>(static_cast<vector<int>&&>(items));
数值类型的转换
- 用法作用和
C
的(T)
强制类型转换一样,不会对结果进行检查,这里涉及到大小字节之间转换的正确性需要程序员自己考虑。
char ch1 = 'a';
int i = static_cast<int>(100.04);
ch1 = static_cast<char>(i);
基类指向子类的成员变量或函数
- 这类方法一般会用在回调时,使用父类调用子类的函数,调用的是子类的函数。注意实际的对象要是对应的子类才行。
typedef void (C::*FuncHello)();
auto E::*f2 = &E::hello;
(c.*static_cast<FuncHello>(f2))();
typedef void (B::*VirtualFuncHello)();
auto D::*f3 = &D::hello;
(b.*static_cast<VirtualFuncHello>(f3))();
例子
// test-static-cast.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
using namespace std;
struct A
A() cout << "A" << endl;
int a = 1;
void hello() cout << "A hello" << endl;
;
struct B : A
B() cout << "B" << endl;
int b = 2;
virtual void hello() cout << "B hello" << endl;
;
struct C : A
C() cout << "C" << endl;
int c = 3;
void hello() cout << "C hello" << endl;
;
struct D : B
D() cout << "D" << endl;
int d = 4;
void world() cout << "D world" << endl;
void hello() cout << "D hello" << endl;
;
struct E : C
E() cout << "E" << endl;
int e = 5;
void world() cout << "E world" << endl;
void hello() cout << "E hello" << endl;
;
int main()
std::cout << "Hello World!\\n";
// b virtual
cout << " ===== 1 ===== " << endl;
D d;
B& b = d;
b.hello();
B* b1 = &d;
b1->hello();
// e not virtual
cout << " ===== 2 ===== " << endl;
E e;
C& c = e;
c.hello();
C* c1 = &e;
c1->hello();
// 编译错误: 类型转换无效。类类型B和C没有关系。
// C& c2 = static_cast<C&>(b);
// 向下转换, 因为 D 是多态的子类,实际指向的对象还是 D.
cout << " ===== 3 ===== " << endl;
D& d1 = static_cast<D&>(b);
d1.hello();
// 向下转换非多态继承,实际对象是E,所以转换成功。转换为E对象。
cout << " ===== 4 ===== " << endl;
E& e1 = static_cast<E&>(c);
e1.hello();
// A并不是虚父类,构不成多态关系。所以对象指向 a.
cout << " ===== 5 ===== " << endl;
A& a = b;
a.hello();
A& a1 = d;
a.hello();
// 向下转换,不安全的做法,编译器不会检查,打印的实际对象是B. 注意如果调用在B不存在,在D里存在的方法可能会崩溃,未定义行为。
cout << " ===== 6 ===== " << endl;
B b2;
D& d2 = static_cast<D&>(b2);
//因为dynamc_cast动态转换失败会返回0,而0初始化一个引用类型D&会崩溃。
//D& d2_2 = dynamic_cast<D&>(b2);
D* d2_3 = dynamic_cast<D*>(&b2);
assert(d2_3 == NULL);
C c2_1;
// 不是多态类型,编译报错。
//E* e2_1 = dynamic_cast<E*>(&c2_1);
//以下调用可能会崩溃。
//d2.hello();
//以下调用可能会崩溃。
//d2.world();
cout << " ===== 7 ===== " << endl;
C c2;
E& e2 = static_cast<E&>(c2);
//以下调用可能会崩溃。
//e2.hello();
// 左值 lvalue 转换为过期值 xvalue,items已经失效,size是0.
// 有时候需要某些元素添加更长的生命周期,转换为xvalue是最小的代价。
cout << " ===== 8 ===== " << endl;
vector<int> items = 1,2,3;
cout << "items.size(): " << items.size() << endl;
vector<int>* items2 = new vector<int>(static_cast<vector<int>&&>(items));
cout << "items.size(): " << items.size() << " items2.size(): " << items2->size() << endl;
for (int v : *items2)
cout << "v: " << v << endl;
delete items2;
// 丢掉返回值.
cout << " ===== 9 ===== " << endl;
static_cast<void>(items.size());
// 和C一样(T)可以强转类型, 除了 const,volatile, __unaligned 声明的属性。
// 支持数值类型的转换, 作用和(T)一样。不过这种可以直接用(T)即可。
cout << " ===== 10 ===== " << endl;
char ch1 = 'a';
cout << "ch1: " << ch1 << endl;
int i = static_cast<int>(100.04);
cout << "i: " << i << endl;
ch1 = static_cast<char>(i);
cout << "ch1: " << ch1 << endl;
// 支持void*指针转换.
cout << " ===== 11 ===== " << endl;
void* fp = &i;
int* ni = static_cast<int*>(fp);
cout << "ni: " << *ni << endl;
// 支持成员(变量和函数)指针向上转换(向父类). a1的实际对象是D, 通过父对象调用子函数和成员。
cout << " ===== 12 ===== " << endl;
int D::*f1 = &D::d;
cout << "a1.d: " << a1.*static_cast<int A::*>(f1) << endl;
cout << " ===== 13 ===== " << endl;
c.hello();
typedef void (C::*FuncHello)();
auto E::*f2 = &E::hello;
(c.*static_cast<FuncHello>(f2))();
typedef void (B::*VirtualFuncHello)();
auto D::*f3 = &D::hello;
(b.*static_cast<VirtualFuncHello>(f3))();
输出
Hello World!
===== 1 =====
A
B
D
D hello
D hello
===== 2 =====
A
C
E
C hello
C hello
===== 3 =====
D hello
===== 4 =====
E hello
===== 5 =====
A hello
A hello
===== 6 =====
A
B
A
C
===== 7 =====
A
C
===== 8 =====
items.size(): 3
items.size(): 0 items2.size(): 3
v: 1
v: 2
v: 3
===== 9 =====
===== 10 =====
ch1: a
i: 100
ch1: d
===== 11 =====
ni: 100
===== 12 =====
a1.d: 4
===== 13 =====
C hello
E hello
D hello
参考
以上是关于[C/C++]_[中级]_[static_cast的详细解析]的主要内容,如果未能解决你的问题,请参考以下文章
[C/C++]_[中级]_[static_cast的详细解析]
[C/C++]_[初级]_[static_cast,reinterpret_cast,dynimic_cast的使用场景和区别]
错误 C2440: 'static_cast' : 无法从 'UINT (__thiscall CImportProjectDlg::* )(CPoint)' 转换为 'LRESULT (__this