c++ 继承简介(c++的继承方式)

c++ 继承简介(c++的继承方式)

编码文章call10242025-08-02 15:21:514A+A-

24.1 — 继承简介

2024 年 6 月 5 日

在上一章中,我们讨论了对象组合,即从更简单的类和类型构建复杂类。对象组合非常适合构建与其部分具有“has-a”关系的新对象。但是,对象组合只是 C++ 允许您构建复杂类的两种主要方式之一。第二种方式是通过继承,它模拟了两个对象之间的“is-a”关系。

与对象组合(通过组合和连接其他对象来创建新对象)不同,继承是通过直接获取其他对象的属性和行为,然后扩展或专门化它们来创建新对象。与对象组合一样,继承在现实生活中无处不在。当你受孕时,你继承了父母的基因,并从他们两人那里获得了身体属性——但随后你又在上面添加了自己的个性。技术产品(计算机、手机等)继承了其前身的特性(通常用于向后兼容)。例如,英特尔奔腾处理器继承了英特尔 486 处理器定义的许多特性,而英特尔 486 处理器本身又继承了早期处理器的特性。C++ 从其所基于的语言 C 继承了许多特性,而 C 从它之前的编程语言继承了许多特性。

以苹果和香蕉为例。虽然苹果和香蕉是不同的水果,但它们的共同点是它们都是水果。而且由于苹果和香蕉是水果,简单的逻辑告诉我们,任何适用于水果的事情也适用于苹果和香蕉。例如,所有水果都有名称、颜色和大小。因此,苹果和香蕉也有名称、颜色和大小。我们可以说苹果和香蕉继承(获得)了水果的所有属性,因为它们水果。我们还知道水果要经过成熟过程才能食用。因为苹果和香蕉是水果,所以我们还知道苹果和香蕉会继承成熟的行为。

用图表来表示的话,苹果、香蕉和水果之间的关系可能看起来像这样:

该图定义了一个层次结构。

层次结构

层次结构是一种显示各种对象如何关联的图表。大多数层次结构要么显示随时间推移的进展(386 -> 486 -> Pentium),要么以从一般到具体的方式对事物进行分类(水果 -> 苹果 -> 蜜脆)。如果您学过生物学,那么著名的领域、界、门、纲、目、科、属和物种排序定义了一个层次结构(从一般到具体)。

这是层次结构的另一个示例:正方形是矩形,矩形是四边形,四边形是一种形状。直角三角形是三角形,三角形也是一种形状。将其放入层次结构图中,如下所示:

该图从一般(顶部)到具体(底部),层次结构中的每个项目都继承了其上方项目的属性和行为。

展望未来

在本章中,我们将探讨 C++ 中继承工作原理的基础知识。

下一章,我们将探讨继承如何通过虚函数实现多态性(面向对象编程的流行语之一)。

随着我们的进展,我们还将讨论继承的主要好处以及一些缺点。

在上一章中,我们讨论了对象组合,即通过组合和连接其他类和类型来构建复杂的类。对象组合非常适合构建与其部分具有“拥有”关系的新对象。然而,对象组合只是C++允许你构建复杂类的两种主要方式之一。第二种方式是通过继承,它在两个对象之间模拟“是一种”的关系。

与涉及通过组合和连接其他对象来创建新对象的对象组合不同,继承涉及通过直接获取其他对象的属性和行为,然后扩展或专门化它们来创建新对象。与对象组合一样,继承在现实生活中无处不在。当你被孕育时,你从父母那里继承了基因,并从他们那里获得了身体特征——但后来你在上面添加了自己的个性。科技产品(计算机、手机等)从其前身继承特性(通常用于向后兼容)。例如,英特尔奔腾处理器继承了许多由英特尔486处理器定义的特性,而英特尔486处理器本身又从早期处理器继承了许多特性。C++从C语言继承了许多特性,C语言是基于它的编程语言,而C语言又从前面的编程语言继承了许多特性。

考虑苹果和香蕉。尽管苹果和香蕉是不同的水果,但它们都有一个共同点,那就是它们都是水果。因为苹果和香蕉是水果,简单的逻辑告诉我们,所有关于水果的事实也适用于苹果和香蕉。例如,所有的水果都有名称、颜色和大小。因此,苹果和香蕉也有名称、颜色和大小。我们可以说苹果和香蕉继承(获得)了水果的所有属性,因为它们是水果。我们还知道,水果会经历一个成熟过程,从而变得可食用。因为苹果和香蕉是水果,我们也知道苹果和香蕉将继承成熟的特性。

将其放入图表中,苹果、香蕉和水果之间的关系可能如下所示:

水果
|
|--- 苹果
|--- 香蕉

在这个图表中,水果类位于顶部,苹果和香蕉类继承自它。这表示水果与苹果/香蕉之间的“是一种”的关系。就像在例子中一样,水果类中定义的任何属性或方法都将被苹果和香蕉类继承。

现在让我们看看这在C++中是如何应用的:

class Fruit {
public:
    std::string name;
    std::string color;
    int size;

    void ripen() {
        // 成熟逻辑在这里
    }
};

class Apple : public Fruit {
    // 苹果特有的附加属性或方法
};

class Banana : public Fruit {
    // 香蕉特有的附加属性或方法
};

在这个C++示例中,苹果和香蕉类都使用:符号后跟public关键字继承自水果类,这表示公共继承。这意味着水果类中的所有公共和保护成员都可以在派生类(苹果和香蕉)中访问。

现在你可以创建苹果和香蕉类的对象,并访问水果类中定义的属性和方法:

Apple apple;
apple.name = "Apple";
apple.color = "Red";
apple.size = 100;
apple.ripen();

Banana banana;
banana.name = "Banana";
banana.color = "Yellow";
banana.size = 150;
banana.ripen();

通过使用继承,你可以创建更专业的类,同时重用基类中定义的属性和行为,从而促进代码的重用和组织。

Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) {
  *dbptr = nullptr;

  DBImpl* impl = new DBImpl(options, dbname);
  impl->mutex_.Lock();
  VersionEdit edit;
  // Recover handles create_if_missing, error_if_exists
  bool save_manifest = false;
  Status s = impl->Recover(&edit, &save_manifest);
  if (s.ok() && impl->mem_ == nullptr) {
    // Create new log and a corresponding memtable.
    uint64_t new_log_number = impl->versions_->NewFileNumber();
    WritableFile* lfile;
    s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),
                                     &lfile);
    if (s.ok()) {
      edit.SetLogNumber(new_log_number);
      impl->logfile_ = lfile;
      impl->logfile_number_ = new_log_number;
      impl->log_ = new log::Writer(lfile);
      impl->mem_ = new MemTable(impl->internal_comparator_);
      impl->mem_->Ref();
    }
  }
  if (s.ok() && save_manifest) {
    edit.SetPrevLogNumber(0);  // No older logs needed after recovery.
    edit.SetLogNumber(impl->logfile_number_);
    s = impl->versions_->LogAndApply(&edit, &impl->mutex_);
  }
  if (s.ok()) {
    impl->RemoveObsoleteFiles();
    impl->MaybeScheduleCompaction();
  }
  impl->mutex_.Unlock();
}
点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4