基类指针指向派生类对象

本文详细解析了C++中基础类与派生类指针调用成员函数的行为特性,介绍了静态联编与动态联编的区别,并重点阐述了虚函数的作用及其实现原理,包括纯虚函数和抽象类的概念。

父类子类指针函数调用注意事项
1,如果以一个基础类指针指向一个衍生类对象(派生类对象),那么经由该指针只能访问基础类定义的函数(静态联翩)
 

2,如果以一个衍生类指针指向一个基础类对象,必须先做强制转型动作(explicit cast),这种做法很危险,也不符合生活习惯,在程序设计上也会给程序员带来困扰。(一般不会这么去定义)
 

3,如果基础类和衍生类定义了相同名称的成员函数,那么通过对象指针调用成员函数时,到底调用那个函数要根据指针的原型来确定,而不是根据指针实际指向的对象类型确定。
 

虚拟函数就是为了对“如果你以一个基础类指针指向一个衍生类对象,那么通过该指针,你只能访问基础类定义的成员函数”这条规则反其道而行之的设计。
 

如果你预期衍生类由可能重新定义一个成员函数,那么你就把它定义成虚拟函数( virtual )。

polymorphism就是让处理基础类别对象的程序代码能够通透的继续适当地处理衍生类对象。


纯虚拟函数:

virtual void myfunc ( ) =0;

纯虚拟函数不许定义其具体动作,它的存在只是为了在衍生类钟被重新定义。只要是拥有纯虚拟函数的类,就是抽象类,它们是不能够被实例化的(只能被继承)。如果一个继承类没有改写父类中的纯虚函数,那么他也是抽象类,也不能被实例化。

抽象类不能被实例化,不过我们可以拥有指向抽象类的指针,以便于操纵各个衍生类。

虚拟函数衍生下去仍然是虚拟函数,而且还可以省略掉关键字“virtual”。

#include <iostream> 
using namespace std; 
class A 
{ 
public: 
    virtual void foo() 
    { 
        cout << "A's foo()" << endl; 
        bar(); 
    } 
    virtual void bar() 
    { 
        cout << "A's bar()" << endl; 
    } 
}; 
class B: public A 
{ 
public: 
    void foo() 
    { 
        cout << "B's foo()" << endl; 
        A::foo(); 
    } 
    void bar() 
    { 
        cout << "B's bar()" << endl; 
    } 
}; 
int main() 
{ 
    B bobj; 
    A *aptr = &bobj; 
    aptr->foo(); 
    A aobj = *aptr; //转化为A类对象
    aobj.foo(); 
} 
 
 
aptr->foo()输出结果是:
   B's foo()//这个明白,多态性
   A's foo()//这个也明白,执行A::foo();
   B's bar()//虽然调用的是这个函数:A::foo(); 但隐式传入的还是bobj 的地址,所以再次调用bar();调用时还是会调用B的函数, 与虚函数指针有关
 
aobj.foo()//输出结果是:
  A's foo() //这个不是指针,aobj完全是一个A的对象,与多态没有关系
  A's bar() 

 

<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 { /*...*/ } }; ```
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值