继承 基类和派生类指针

1,直接用基类指针引用基类对象
2,直接用派生类指针引用派生类对象
3,用基类指针引用一个派生类对象,由于派生类对象也是基类的对象,所以这种引用是安全的,
但是只能引用基类成员。若试图通过基类指针引用那些只在派生类中才有的成员,编译器会报告语法错误。(解决该问题的答案是虚函数和多态性)
4,用派生类指针引用基类的对象。这种引用方式会导致语法错误。派生类指针必须先强制转换为基类指针,这种方法是安全的。 

而在侯捷的深入浅出MFC中第二章C++重要性质中:
1、如果你以一个"基类之指针"指向一个"派生类之对象",那么经由该指针你只能调用该基类所定义的函数
2、如果你以一个“派生类之指针”指向一个“基类之对象”,你必须先做明显的转型操作(explicit cast),这种作法很危险。
3、如果基类和派生类都定义了“相同名称之函数”,那么通过对象指针调用成员函数时,到底调用了那个函数,必须视该指针的原始类型而定,而不是视指针实际所指的对象的类型而定,这与第1点其实意义相通。

#include <iostream>
#include <stdlib.h>

using namespace std;

class A
{
public:
  char str[20];
  void f(){cout<<"class A"<<endl;}
  void fff(){cout<<"class A's str "<<str<<endl;}  
  void add(){cout<<"class A address: "<<this<<endl;}
};

class B:public A
{
public:
  int i;
  char sb[20];
  B(){cout<<"class B constructor is run."<<endl;}
  ~B(){cout<<"class B destructor is run."<<endl;}
  void f(){cout<<"class B"<<endl;}
  void ff(){cout<<"class B "<<i<<str<<sb<<endl;}
  void add(){cout<<"class B address: "<<this<<endl;}
};

int main(int argc, char *argv[])
{
  //声明父类对象 
  A b;
  //声明父类对象的指针,指向父类对象 
  A *pa=&b;
  pa->add();
  //这个写法正确,不过很危险,因为pa到底是指向B还是A是不确定的.如果能明确的知道
  //pa是指向B类对象的,就如现在写的这个,那么没问题,如果pa指向A类对象,就会存在
  //风险.改变指针的类型,并不会影响内存分配既不会调用构造函数

  B *pb=(B *)pa;
  //类型强制转化后,指向的地址相同. 但会按转化类型访问数据成员.
  //成员函数属于类而不属于对象.各对象共用类的成员函数.强制转换成 B 类型后,可
  //调用类的成员函数。编译pb->add();后的代码只是调用add函数的时候传入了pb的对
  //象指针this
  pb->add();

  //由于pa指向的是父类对象的地址,这个指针被强制转换为派生类指针后,会出现内存越
  //界访问的情况,是不安全的. 
  pb->i=100;
  char dsd[100];
  strcpy(pb->sb, " class B's sb.");
  strcpy(pb->str, " class A's str.");

  //pb->f()调用的具体函数,视指针的原始类型而定,而不是视指针实际所指的对象的
  //类型而定.如果是虚函数,则视实际所指的对象的类型而定 
  pb->f();
  pb->ff();
  pb->fff();

  system("PAUSE"); 
  return 0;
}

<think>好的,我现在要回答用户关于C++基类指针指向派生类对象的用法注意事项的问题。首先,我需要回顾用户提供的引用内容,确保回答准确并涵盖关键点。 用户提到了四个引用,涉及多态、智能指针、类型转换继承中的构造函数顺序。首先,我需要将这些信息整合起来。基类指针指向派生类对象是多态的核心,允许通过基类接口操作派生类对象。注意事项应包括虚函数的使用、内存管理、类型转换对象切片等问题。 接下来,按照用户的要求,结构要清晰,分点说明。可能需要分为基本用法、多态实现、注意事项、示例代码相关问题几个部分。需要确保所有代码示例正确,符合C++语法,特别是虚函数智能指针的使用。 在注意事项中,要提到虚析构函数的重要性,避免对象切片,正确使用类型转换(如dynamic_cast),以及智能指针的管理。同时,构造函数析构函数的调用顺序可能影响程序行为,需要根据引用4中的例子说明虚继承的影响。 示例代码部分,需要展示基类指针指向派生类对象的基本用法,多态的实现,以及智能指针的应用。例如,使用unique_ptr管理派生类对象,并通过基类指针调用虚函数。 最后,生成相关问题时要围绕用户的问题扩展,可能涉及多态的原理、动态类型转换、智能指针的使用场景、虚析构函数的重要性等。 需要检查是否符合格式要求,数学表达式使用$...$,独立公式用$$...$$,但这里可能不需要数学公式。确保所有引用正确标注,如引用[^1]、[^2]等,并自然融入回答中。 总结步骤: 1. 介绍基本概念用法 2. 多态的实现方法,虚函数的作用 3. 注意事项分点列出,包括虚析构函数、内存管理、类型转换等 4. 提供示例代码,涵盖普通指针智能指针 5. 生成相关问题,引导深入学习</think>### C++基类指针指向派生类对象的使用方法注意事项 #### 一、基本用法 通过基类指针指向派生类对象是C++多态的核心机制。基类指针可以访问**基类声明**的成员,若需要调用派生类特有的成员,需借助**虚函数**或**类型转换**实现[^1][^3]。 ```cpp class Animal { public: virtual void makeSound() { std::cout << "Animal sound" << std::endl; } }; class Dog : public Animal { public: void makeSound() override { std::cout << "Woof!" << std::endl; } void fetch() { std::cout << "Fetching stick" << std::endl; } }; int main() { Animal* animal = new Dog(); // 基类指针指向派生类对象 animal->makeSound(); // 输出: Woof!(多态) // animal->fetch(); // 错误:基类无此成员 delete animal; return 0; } ``` #### 二、多态实现要点 1. **虚函数机制** 在基类中声明虚函数`virtual`,派生类通过`override`重写实现多态[^3]: ```cpp virtual void show() { ... } // 基类声明 void show() override { ... } // 派生类重写 ``` 2. **动态绑定** 运行时根据对象实际类型调用对应函数,需通过指针/引用调用虚函数才能生效。 #### 三、关键注意事项 1. **虚析构函数** 若通过基类指针删除派生类对象,**必须声明虚析构函数**,否则会导致内存泄漏: ```cpp class Base { public: virtual ~Base() = default; // 虚析构函数 }; ``` 2. **对象切片问题** 当派生类对象**直接赋值给基类对象**时,会发生数据截断: ```cpp Derived d; Base b = d; // 仅复制基类部分数据 ``` 3. **类型安全转换** 使用`dynamic_cast`进行向下转型时需满足: - 基类至少包含一个虚函数(多态类型) - 启用RTTI(运行时类型识别) ```cpp if (auto* dog = dynamic_cast<Dog*>(animal)) { dog->fetch(); // 安全访问派生类成员 } ``` 4. **智能指针管理** 使用`std::unique_ptr`或`std::shared_ptr`时,需注意所有权转移: ```cpp std::unique_ptr<Base> ptr = std::make_unique<Derived>(); ``` 5. **构造/析构顺序** 虚基类的构造函数优先执行,析构顺序构造相反[^4]: ``` 构造顺序:B → D → A → C → E 析构顺序:~E → ~C → ~A → ~D → ~B ``` #### 四、扩展应用示例(智能指针) ```cpp #include <memory> class Device { public: virtual void activate() = 0; virtual ~Device() = default; }; class Printer : public Device { public: void activate() override { std::cout << "Printing..." << std::endl; } void calibrate() { std::cout << "Calibrating printer" << std::endl; } }; int main() { std::unique_ptr<Device> device = std::make_unique<Printer>(); device->activate(); // 多态调用 // 访问派生类特有成员 if (auto* printer = dynamic_cast<Printer*>(device.get())) { printer->calibrate(); } return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值