关于C++父子类转换问题

原则:

  • 父类指针和引用可以指向子类对象 ,而子类对象指针不能直接指向父类,但是可以通过强制转换来把父类指针转换为子类指针。 子类转父类后能访问的函数是父类非虚函数和子类虚函数,父类转子类后能访问到的是子类的非虚函数和继承的父类函数。子类的虚函数并没有隐藏父类的所以访问到的是父类虚函数。eg:
    CFather *pFather = new CFather; //父类指针
    CSon *pSON = static_cast<CSon *>(pFather); //父类转子类
    pSON->eat(); //调用的是父类的虚函数,因为new的是父类的
    pSON->play(); //调用的是子类的非虚函数
  • 爷爷类和孙子类关系同上。
  • 子类向上为隐式转换 父类向下需要用static_cast<> 强转

测试demo如下:
test.h

#pragma once
//爷爷类
class CGrandFather {
public:
	virtual void eat();
	virtual void learn() = 0;

};
//爸爸类
class CFather :public CGrandFather{
public:
	virtual void eat();
	virtual void learn();
	void money();
private:
	void work();
};
//妈妈类
class CMother :public CGrandFather {
public:
	virtual void eat();
	virtual void learn();
	void buetiful();
private:
	void work();
};
//孙子类
class CSon :public CFather ,public CMother{
public:
	virtual void eat();
	virtual void learn();
	void play();
};

test.cpp

#include "test.h"
#include <iostream>
using namespace std;


void CGrandFather::eat()
{
	cout << "GrandFather eat" << endl;
}

void CFather::eat()
{
	cout << "CFather eat" << endl;
}

void CFather::learn()
{
	cout << "CFather learn" << endl;
}

void CFather::money()
{
	cout << "CFather money" << endl;
}

void CFather::work()
{
	cout << "CFather work" << endl;
}

void CSon::eat()
{
	cout << "CSon eat" << endl;
}

void CSon::learn()
{
	cout << "CSon learn" << endl;
}


void CSon::play()
{
	cout << "CSon play" << endl;
}
void CMother::eat()
{
	cout << "CMother eat" << endl;
}

void CMother::learn()
{
	cout << "CMother learn" << endl;
}

void CMother::buetiful()
{
	cout << "CMother buetiful" << endl;
}

void CMother::work()
{
	cout << "CMother work" << endl;
}


int main()
{
//	CGrandFather *pGrandFather = new CSon;  //
//	pGrandFather->learn();
	//CSon * pSon = static_cast<CSon *>(pGrandFather);  //
	//pSon->play();
	CSon *pSon = new CSon;
	CFather *pFather = pSon;
	pFather->money();
	CMother *pMother =static_cast<CSon *> (pFather);	
	pMother->eat();	
//	CSon * pSon2 = static_cast<CSon *>(pFather);
//	pSon2->play();
}





### C++指针强制类型转换的使用方法及注意事项 #### 一、C++ 强制类型转换概述 C++ 提供了四种显式的强制类型转换操作符:`static_cast`、`dynamic_cast`、`reinterpret_cast` 和 `const_cast`。每种转换都有特定的应用场景和限制条件。 #### 二、具体用法与示例 1. **`reinterpret_cast` 的使用** - 这是一种底层的强制类型转换,允许将一种指针类型转换为另一种完全不同的指针类型,或者在指针和整数之间进行转换。 - 它主要用于简单的位级重新解释,例如将一个指针视为另一个类型的地址。 - 示例代码如下: ```cpp long p = 0x12345678; char* cp = reinterpret_cast<char*>(&p); // 将 long 类型变量的地址转换为 char* ``` 2. **`static_cast` 的使用** - 主要用于基本数据类型之间的转换以及具有继承关系的对象间的向上/向下转型(前提是编译器能够静态推断安全性)。 - 对于指针而言,它可用于父子类间的安全转换。 - 示例代码如下: ```cpp class Base {}; class Derived : public Base {}; Derived d; Base* basePtr = static_cast<Base*>(&d); // 向上转型 Derived* derivedPtr = static_cast<Derived*>(basePtr); // 向下转型 ``` 3. **`dynamic_cast` 的使用** - 动态类型转换仅适用于多态对象(即包含虚函数的基类),并依赖运行时检查来验证转换的有效性。 - 如果尝试执行非法的动态转换,则返回空指针或抛出异常。 - 示例代码如下: ```cpp Base* b = new Derived(); Derived* d = dynamic_cast<Derived*>(b); if (d != nullptr) { // 转换成功 } ``` 4. **`const_cast` 的使用** - 此操作符专门用来移除常量属性 (`const`) 或易变属性 (`volatile`)。 - 需要注意的是,修改通过这种方式获得的原生不可变对象可能会引发未定义行为。 - 示例代码如下: ```cpp const int value = 42; int* nonConstValue = const_cast<int*>(&value); *nonConstValue = 99; // 不推荐这样做,因为会破坏原有语义[^1] ``` #### 三、注意事项 - 使用 `reinterpret_cast` 应格外小心,因为它绕过了类型系统的保护机制,可能导致难以调试的问题。除非绝对必要,否则不应随意应用此类转换[^2]。 - 当涉及复杂的继承结构时优先考虑采用 `dynamic_cast` 来代替直接运用 `static_cast` ,从而增强程序健壮性。 - 利用 `const_cast` 修改原本声明为只读的数据需谨慎行事,确保不会违反逻辑约束或触发潜在风险[^3]。 ```cpp // 综合示例展示多种 cast 方式 class Animal { virtual void sound() {} }; class Dog : public Animal { void bark() {} }; int main(){ double pi=3.14f; float fpi = static_cast<float>(pi); Animal* a=new Dog(); Dog* doggy=dynamic_cast<Dog*>(a); delete a; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值