当前位置: 首页 > article >正文

C++抽象类与类继承相关注意事项 [学习笔记]

以下是关于 抽象类类继承 在 C++ 编程中的注意事项总结:


抽象类的注意事项

  1. 定义抽象类

    • 抽象类中包含至少一个纯虚函数:
      virtual 返回类型 函数名(参数列表) = 0;
      
    • 抽象类不能直接实例化。
  2. 虚析构函数

    • 抽象类通常需要定义虚析构函数,以便通过基类指针删除派生类对象时正确释放资源:
      virtual ~Base() {}
      
  3. 成员的种类

    • 抽象类可以包含:
      • 成员变量
      • 普通函数
      • 纯虚函数
      • 构造函数(用于初始化成员)
  4. 接口类

    • 如果抽象类中的所有成员函数都是纯虚函数,通常称之为 接口类,可用于定义行为规范。

类继承的注意事项

  1. 继承方式

    • 公有继承(public):基类的 publicprotected 成员在派生类中保持原有访问权限。
    • 私有继承(private):基类的 publicprotected 成员在派生类中变为 private
    • 受保护继承(protected):基类的 publicprotected 成员在派生类中变为 protected
  2. 派生类的构造与析构

    • 派生类会调用基类的构造函数来初始化继承的成员。
    • 析构时会按继承链逆序调用析构函数(先销毁派生类,再销毁基类)。
  3. 重写与隐藏

    • 如果派生类重写基类的虚函数,需要使用 override 关键字,避免误操作:
      virtual void func() override;
      
    • 如果派生类定义了与基类同名的非虚函数,则基类函数会被隐藏,需显式调用:
      Base::func();
      
  4. 虚函数与动态多态

    • 虚函数通过虚函数表实现动态绑定,基类指针或引用指向派生类对象时,可以正确调用派生类的重写函数。
  5. 纯虚函数的继承

    • 如果派生类未实现所有纯虚函数,则派生类本身仍是抽象类,不能实例化。

多继承的注意事项

  1. 菱形继承问题

    • 当多个基类继承自同一个父类,派生类再次继承这些基类时,可能会导致基类的成员被多次继承。
    • 解决方法:使用虚继承:
      class Base {};
      class Derived1 : virtual public Base {};
      class Derived2 : virtual public Base {};
      class MostDerived : public Derived1, public Derived2 {};
      
  2. 继承冲突

    • 如果多继承中存在同名成员或函数,需通过作用域解析运算符明确指定调用哪个基类的成员:
      class Base1 {
          void func();
      };
      class Base2 {
          void func();
      };
      class Derived : public Base1, public Base2 {
          void someFunc() {
              Base1::func();
          }
      };
      

类型转换的注意事项

  1. 向上转型(Upcasting)

    • 基类指针或引用可以指向派生类对象。
    • 安全并且不需要显式转换。
  2. 向下转型(Downcasting)

    • 将基类指针或引用转换为派生类指针,需要显式转换并确保类型安全(可用 dynamic_cast 检查):
      Derived* d = dynamic_cast<Derived*>(basePtr);
      if (d) {
          d->func();
      }
      

设计注意事项

  1. 基类的职责

    • 基类应设计为接口类或提供通用功能,不应过多关注具体实现。
  2. 派生类的职责

    • 派生类应负责实现基类定义的接口,避免改变基类的设计规范。
  3. 里氏替换原则

    • 任何基类可以出现的地方,都应该可以用派生类替换,而不会改变程序的行为。
  4. 避免多继承复杂性

    • 多继承的设计容易引入复杂性,尽量使用组合或接口类代替。

示例:抽象类与继承的综合使用

#include <iostream>
using namespace std;

// 抽象基类
class Shape {
public:
    virtual void draw() = 0; // 纯虚函数
    virtual double area() = 0;
    virtual ~Shape() {}
};

// 派生类 - 圆形
class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    void draw() override {
        cout << "Drawing Circle" << endl;
    }
    double area() override {
        return 3.14159 * radius * radius;
    }
};

// 派生类 - 矩形
class Rectangle : public Shape {
private:
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    void draw() override {
        cout << "Drawing Rectangle" << endl;
    }
    double area() override {
        return width * height;
    }
};

int main() {
    Shape* shapes[] = {new Circle(5.0), new Rectangle(4.0, 6.0)};
    for (Shape* shape : shapes) {
        shape->draw();
        cout << "Area: " << shape->area() << endl;
        delete shape; // 动态删除
    }
    return 0;
}

输出

Drawing Circle
Area: 78.5397
Drawing Rectangle
Area: 24


http://www.kler.cn/a/451456.html

相关文章:

  • 细说STM32F407单片机轮询方式读写SPI FLASH W25Q16BV
  • 面试场景题系列:设计一致性哈希系统
  • 瑞吉外卖项目学习笔记(七)新增菜品、(批量)删除菜品
  • GTID下复制问题和解决
  • 网络安全攻防演练中的常见计策
  • YOLO模型格式转换:pt -> onnx -> rknn
  • select 1 from table的作用 详解
  • 【ue5学习笔记2】在场景放入一个物体的蓝图输入事件无效?
  • sentinel学习笔记8-系统自适应与黑白名单限流
  • LabVIEW实现GSM/GPRS通信
  • LeetCode 3138.同位字符串连接的最小长度:计数(一个数最多128个因数)
  • Python中定位元素包含文本信息的详细解析与代码示例
  • QWebChannel实现与JS的交互
  • 使用React构建一个掷骰子的小游戏
  • skywalking 搭建
  • 【漫话机器学习系列】016.误差中的偏差(BIAS)
  • 【漏洞复现】CVE-2015-5531 Arbitrary File Reading
  • 序列化和反序列化(二)
  • ML-Agents 概述(二)
  • windows C++ TCP客户端
  • 类设计者的核查表
  • 微软远程桌面APP怎么用
  • 算法专题——双指针
  • 机器学习之scikit-learn(简称 sklearn)
  • ensp 关于acl的运用和讲解
  • 鸿蒙 log抓取