C++如何把基类指针转换为子类指针&强制类型转换

发布于:2024-10-12 ⋅ 阅读:(8) ⋅ 点赞:(0)

在C++中,可以使用 dynamic_cast运算符将基类指针转换为子类指针。dynamic_cast是一种安全的转换方式,它会在运行时检查转换是否合法。

假设有一个基类Base和一个派生类Derived,可以按以下方式进行转换:

Base* basePtr = new Derived(); // 创建派生类对象,并将其赋值给基类指针

Derived* derivedPtr =dynamic cast<Derived*>(basePtr); // 将基类指针转换为派生类指针
if (derivedPtr){
// 转换成功,可以使用派生类指针进行操作...
}else {
// 转换失败,基类指针不指向派生类对象...
}

需要注意的是,dynamic_cast只能用于具有多态性的类层次结构,即基类必须至少有一个虚函数。此外dynamic_cast只能用于指针或引用类型的转换,不能用于转换对象本身
如果转换成功,dynamic_cast将返回指向派生类对象的指针;如果转换失败,dynamic_cast将返回空指针(nullptr)。因此,在进行dynamic_cast转换后,最好使用条件语句来检查转换的结果,以避免使用空指针进行操作。

参考:C++之强制类型转换_c++强制类型转换-CSDN博客

四种强制类型转换

static_cast:静态转换是最常用的一种类型转换,它可以在不同但相关的类型之间进行转换,如基本数据类型之间的转换、父类指针向子类指针的转换等。但是需要注意的是,静态转换没有运行时类型检查,因此在进行转换时需要确保类型之间是相关的,否则可能会导致错误。

dynamic_cast:动态转换主要用于类层次结构中的指针或引用类型之间的转换。它在运行时进行类型检查,只有当类型之间存在继承关系时才能进行转换。如果转换失败,即目标类型不是源类型的派生类或基类,则返回空指针(对于指针类型)或抛出std::bad_cast异常(对于引用类型)。

const_cast:常量转换主要用于去除指针或引用类型的常量属性。它可以将const修饰的对象转换为非const修饰的对象,从而可以修改原本被限制为只读的对象。

reinterpret_cast :重新解释转换是一种较为底层的转换方式,它可以将一个指针或引用类型转换为另一个不相关的指针或引用类型。这种转换方式非常危险,因为它不会进行任何类型检查,可能会导致未定义的行为。

static_cast

用法:static_cast<new_type> ( expression )

该运算符把expression转换为new_type类型。

int main(){
	// C语言的强制类型转换
	int aa = 10;
	int ab = 3;
	double result_1 = (double)aa / (double)ab;
 
	// C++的强制类型转换
	int ac = 10;
	int ad = 3;
	double result_2 = static_cast<double>(ac) / static_cast<double>(ad);
	cout << "result_1: " << result_1 << ", result_2: " << result_2 << endl;
 
	char ae = 'a';
	short af = 10;
	int ah = static_cast<int>(ae);
	int ai = static_cast<short>(af);
	cout << "ah: " << ah << ", ai: " << ai << endl;
 
	int aj = 20;
	const int ak = static_cast<const int>(aj);
	cout << "ak: " << ak << endl;
}

 输出:

result_1: 3.33333, result_2: 3.33333
ah: 97, ai: 10
ak: 20

派生类和基类指针互相转换 

#include <iostream>
using namespace std;
class Base {
public:
	int a;
	void fun1() { cout << "Base::fun1" << endl; }
	void fun2() { cout << "Base::fun2" << endl; }
};
class Derive : public Base {
public:
	int b;
	void fun2() { cout << "Derive::fun2" << endl; }
	void fun4() { cout << "Derive::fun4" << endl; }
};
 
int main(){
	Base al;
	Derive am;
	Base* an = static_cast<Base*>(&am);       //派生类指针->父类指针
	Derive* au = static_cast<Derive*>(&al);   //父类指针->派生类指针
 
	an->fun1();   // 调用父类的fun1
	an->fun2();   // 调用父类的fun2
	//an->fun4(); // 编译错误:error: no member named 'fun4' in 'Base'。 
    //因为fun4是派生类的成员函数,只能通过派生类对象进行访问。
 
	au->fun1();   // 调用父类的fun1
	au->fun2();   // 调用派生类的fun2
	au->fun4();   // 调用派生类的fun4,fun4是派生类的成员函数,而不是父类的成员函数
 
	return 0;
}

输出:

Base::fun1
Base::fun2
Base::fun1
Derive::fun2
Derive::fun4

dynamic_cast

用法:dynamic_cast<new_type> ( expression )

dynamic_cast专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。

dynamic_cast 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。向上转型(派生类转基类)是无条件的,不会进行任何检测,所以都能成功;向下转型的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。

dynamic_cast与static_cast是相对的,dynamic_cast是“动态转换”的意思,static_cast是“静态转换”的意思。dynamic_cast会在程序运行期间借助RTTI进行类型转换,这就要求基类必须包含虚函数。static_cast在编译期间完成类型转换,能够更加及时地发现错误。

#include <iostream>
 
class Base {
public:
    virtual ~Base() {}
};
 
class Derived : public Base {
public:
    void DerivedMethod() {
        std::cout << "Derived method called." << std::endl;
    }
};
 
int main() {
    Base* da = new Derived;
    Derived* db = dynamic_cast<Derived*>(da);  // 基类转派生类
    if (db)  db->DerivedMethod();
    else  std::cout << "dynamic_cast failed." << std::endl;
 
    delete da;
    return 0;
}

结果:

Derived method called.

const_cast

用法:const_cast<new_type> ( expression )

该运算符仅用于进行去除const属性的转换,它也是四个强制类型转换运算符中唯一能够去除 const属性的运算符。将const引用转换为同类型的非const引用,将const指针转换为同类型的非const指针。

#include <iostream>
#include <typeinfo>
using namespace std;
 
int main(){
	//移除const限定
	const int ia = 10;
	int* ib = const_cast<int*>(&ia);
	cout << "ib: " << *ib << endl;
 
	//添加const限定
	int ic = 42;
	const int* id = const_cast<const int*>(&ic);
	cout << "id: " << *id << endl;
 
	return 0;
}

结果:

ib: 10
id: 42

reinterpret_cast

用法: reinterpret_cast<new_type> ( expression )

用于将一个指针类型转换为其它的指针类型,但它不改变其操作数的比特表示,只进行了最外层的转换,没有进行二进制的解释。这种转换的结果会导致实际编程中的指针指向的内容是不明确的,因此需要开发者自行确保转换的安全性。应谨慎使用。

#include <iostream>
#include <typeinfo>
using namespace std;
 
int main(){
    int ra = 10;
    int* rb = &ra;
 
    // 将 int* 转换为 double*
    double* rc = reinterpret_cast<double*>(rb);
    cout << "rc: " << *rc << endl;
 
    // 将 int* 转换为 char*
    char* rd = reinterpret_cast<char*>(rb);
    cout << "rd: " << *rd << endl;
	return 0;
}

 结果:

rc: -9.25596e+61
rd: