基类指针指向派生类是安全的,而派生类指向基类则是不安全的

本文探讨了C++中多态性的实现原理,重点介绍了基类与派生类之间的内存布局及其对指针操作的影响。通过具体示例,解析了如何通过虚函数实现多态,并说明了基类指针指向派生类对象时的行为特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
using namespace std;
class A  
{  
int x;  
public:  
A(int i){x=i;}  
virtual ~A(){};
virtual void dispa(){cout<<"x="<<x<<endl;}  
};  


class B:public A  
{  
int y;  
public:  
B(int i, int j):A(i){ y=j;}  
void dispb(){cout<<"y="<<y<<endl;} 
virtual void fun(){};
};  
int _tmain(int argc, _TCHAR* argv[])
{
A a(10), *p;  
B b(20, 30);  
p = &a;  
p->dispa();  
p = &b;  
p->dispa();
cout<<"sizeof(A)="<<sizeof(A)<<endl;
cout<<"sizeof(B)="<<sizeof(B)<<endl;
return 0;

}


一个类或类对象只分配一个vptr的地址。

从内存上来看

A
---------|
|占一个int数据大小--|
|----(x数据)------|
|---------
B则是
---------|---------
|占一个int数据大小--|占一个Int数据大小--|
|从A中继承而来------|---(y数据----------|
|------------------
当定义一个基类类型的指针时
A *p;这时,这个指针指向的是A类型的数据
当p指针指向派生类的时候,因为p是A类型的指针,所以*p只解释为A类型数据的长度,即
————————-|---------
|占一个int数据大小--|占一个Int数据大小--|
|从A中继承而来------|-----(y数据)-------|
|------------------
|------------|------------| 
|-p只指向这个区域-|

因此,当基类的指针(P)指向派生类的时候,只能操作派生类中从基类中继承过来的数据和基类自身的数据。
而派生类指向基类的指针,因为内存空间比基类长,会导致严重的后果,所以不允许派生类的指针指向基类,虽然通过强制转换是可以编译通过的,但这是极不安全的做法。

C++的多态性能解决基类指针不能操作派生类的数据成员的问题


<think>嗯,用户问的是C++中基类指针指向派生类对象的用法和原理,特别是多态相关的。首先我得回忆一下C++的多态机制。记得多态需要虚函数,基类指针指向派生类对象时,如果调用的是虚函数,就会动态绑定到派生类的实现。这点和用户提供的引用内容里的信息一致,比如引用[2]提到必须用虚函数并通过指针或引用操作。 然后用户可能想知道具体怎么用。比如如何声明基类指针,如何指向派生类对象,还有注意事项。引用[3]里提到,如果派生类覆盖了基类的成员函数,基类指针只能访问基类的版本,除非是虚函数。这可能是一个常见的误区,需要解释清楚虚函数的作用。 接下来要考虑用户可能的疑惑点。比如,为什么必须用指针或引用才能实现多态?直接使用对象会会有问题?这里可能需要解释对象切片的问题,当派生类对象被赋值给基类对象时,会丢失派生类的部分,导致无法实现多态。 另外,用户可能想知道动态联编和静态联编的区别。动态联编是在运行时确定调用的函数,而静态联编是在编译时。虚函数表的概念可能也需要简要提及,这样用户能理解背后的机制。 然后,用户提供的示例代码中有非虚函数的情况,这时候基类指针调用的是基类的方法,而使用虚函数后才会调用派生类的方法。这需要对比说明,让用户明白虚函数的关键作用。 可能还需要提到纯虚函数和抽象基类,这样用户知道如何强制派生类实现某些接口。但用户的问题可能更基础,先集中在普通虚函数的使用上。 最后,用户可能想知道实际应用中的例子,比如工厂模式或者策略模式中使用基类指针来管理同的派生类对象,提高代码的扩展性和维护性。 总结下来,回答的结构应该是先解释概念,再说明实现条件,然后给出代码示例对比有无虚函数的情况,接着讨论注意事项,最后提到应用场景。这样用户能逐步理解多态的实现机制和使用方法。</think>### C++基类指针指向派生类对象的原理与多态实现 #### 一、核心概念说明 1. **基类指针指向派生类对象**是C++实现运行时多态的关键机制,需满足: - 基类包含至少一个虚函数(virtual关键字修饰) - 派生类重写(override)了基类的虚函数 - 通过基类指针或引用访问对象 2. **动态联编**原理: ```cpp class Animal { public: virtual void sound() { cout << "Animal sound" << endl; } // 虚函数表指针产生 }; class Dog : public Animal { public: void sound() override { cout << "Bark" << endl; } // 覆盖虚函数表项 }; ``` 当`Animal* animal = new Dog();`时,虚函数表指针指向Dog类的虚函数表[^2] #### 二、具体用法示例 ```cpp #include <iostream> using namespace std; // 基类定义 class Shape { public: virtual void draw() { // 必须声明为虚函数 cout << "Drawing Shape" << endl; } }; // 派生类 class Circle : public Shape { public: void draw() override { // 重写虚函数 cout << "Drawing Circle" << endl; } }; int main() { Shape* shapePtr = new Circle(); // 基类指针指向派生类对象 shapePtr->draw(); // 输出"Drawing Circle" delete shapePtr; return 0; } ``` *输出结果证明多态生效,实际调用的是派生类方法[^2]* #### 三、关键注意事项 1. **对象切片问题**: ```cpp Circle circle; Shape shape = circle; // 对象切片,丢失派生类信息 shape.draw(); // 输出"Drawing Shape" ``` 只有通过指针/引用才能保持多态特性[^3] 2. **访问权限限制**: - 基类指针只能访问基类中声明的成员 - 需要访问派生类特有成员时,需使用`dynamic_cast`: ```cpp if (Circle* c = dynamic_cast<Circle*>(shapePtr)) { c->specialMethod(); // 访问派生类特有方法 } ``` 3. **虚析构函数原则**: ```cpp class Base { public: virtual ~Base() {} // 必须声明虚析构函数 }; ``` 否则通过基类指针删除派生类对象时,会导致资源泄漏[^3] #### 四、多态类型对比 | 特性 | 静态多态(函数重载) | 动态多态(虚函数) | |-------------------|----------------------|--------------------| | 绑定时间 | 编译时 | 运行时 | | 实现方式 | 函数重载/模板 | 虚函数表 | | 性能开销 | 无额外开销 | 虚表查找开销 | | 应用场景 | 编译时确定类型 | 运行时类型变化 | #### 五、典型应用场景 1. **工厂模式**: ```cpp class Product { public: virtual void operation() = 0; }; class ConcreteProduct : public Product { void operation() override { /*...*/ } }; Product* factory() { return new ConcreteProduct(); } ``` 2. **插件架构**: ```cpp // 接口类 class Plugin { public: virtual void execute() = 0; }; // 动态加载的派生类 class MyPlugin : public Plugin { void execute() override { /*...*/ } }; ``` 3. **GUI事件处理**: ```cpp class Widget { public: virtual void onClick() = 0; }; class Button : public Widget { void onClick() override { /*...*/ } }; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值