C++中如何使用子类的指针指向父类的对象
在 C++ 中,基类指针可以指向派生类对象的核心原因是 **“is-a” 关系 **(派生类是基类的一种特殊形式)。这种机制是实现多态的基础,下面从前提、语法、特性、应用及注意事项展开说明。
一、前提:public 继承
基类指针能指向派生类对象的前提是子类必须以public
方式继承父类(这一点非常重要)。
- 若为
private
或protected
继承,派生类与基类的 “is-a” 关系被隐藏,编译器不允许基类指针指向派生类对象(隐式转换被禁止)。
二、语法:直接赋值
当满足public
继承时,基类指针指向派生类对象的语法非常直接:用派生类对象的地址为基类指针赋值。
示例代码:
#include <iostream>
using namespace std;// 基类
class Base {
public:int baseNum;void baseFunc() {cout << "Base::baseFunc()" << endl;}
};// 派生类(public继承基类)
class Derived : public Base {
public:int derivedNum; // 派生类新增成员void derivedFunc() { // 派生类新增函数cout << "Derived::derivedFunc()" << endl;}
};int main() {Derived d; // 定义派生类对象Base* ptr = &d; // 基类指针指向派生类对象(合法,因public继承)return 0;
}
从主函数中,可以看出,先声明一个子类Derived的实例对象,然后再声明一个父类的指针,然后直接将子类的值,赋值给基类的指针。(这里需要注意:实例对象的变量名!=首个成员变量的地址,结构体的实例对象也是如此,变量名实例对象的变量名!=首个成员变量的地址)
三、核心特性:访问范围受限
基类指针指向派生类对象后,只能访问派生类中 “从基类继承的成员”(包括成员变量和成员函数),无法直接访问派生类新增的成员(除非强制类型转换,但不推荐)。
原因:编译器仅知道指针的类型是 “基类”,编译时会根据指针类型(而非指向对象的实际类型)检查访问权限。
示例说明:
int main() {Derived d;Base* ptr = &d;// 合法:访问从基类继承的成员ptr->baseNum = 10; ptr->baseFunc(); // 错误:无法访问派生类新增成员(编译器不知道这些成员的存在)// ptr->derivedNum = 20; // 编译报错// ptr->derivedFunc(); // 编译报错return 0;
}
四、关键应用:结合虚函数实现多态
当基类中存在虚函数时,基类指针指向派生类对象后,调用虚函数会触发动态绑定(运行时根据对象实际类型调用对应的函数版本),这是多态的核心。
示例代码:
class Base {
public:// 基类声明虚函数virtual void vfunc() {cout << "Base::vfunc()" << endl;}
};class Derived : public Base {
public:// 派生类重写(override)虚函数void vfunc() override {cout << "Derived::vfunc()" << endl;}
};int main() {Derived d;Base* ptr = &d; // 基类指针指向派生类对象ptr->vfunc(); // 输出:Derived::vfunc()(动态绑定,调用派生类版本)return 0;
}
原理:虚函数通过 “虚函数表” 实现,基类指针指向派生类对象时,会访问派生类的虚函数表,从而调用派生类的重写版本。
五、注意事项
-
析构函数需设为虚函数若基类指针指向派生类对象,且通过该指针
delete
对象时,若基类析构函数不是虚函数,会导致派生类部分未被析构(内存泄漏)。因此需将基类析构函数声明为虚函数:cpp
运行
class Base { public:virtual ~Base() { cout << "Base::~Base()" << endl; } // 虚析构 };class Derived : public Base { public:~Derived() override { cout << "Derived::~Derived()" << endl; } };int main() {Base* ptr = new Derived(); delete ptr; // 正确:先调用Derived::~Derived(),再调用Base::~Base()return 0; }
-
避免强制转换的风险若通过
static_cast<Derived*>
将基类指针强制转换为派生类指针,虽然能访问派生类新增成员,但如果指针实际指向的是基类对象,会导致未定义行为(如访问非法内存)。
总结
基类指针指向派生类对象是 C++ 多态的基础,其核心是public
继承下的 “is-a” 关系。通过该机制,可统一用基类指针管理不同派生类对象,并结合虚函数实现 “同一接口,不同实现”。使用时需注意访问范围、虚析构函数等细节,避免内存问题。