当前位置:首页 > 技术 > 正文内容

C++ 类继承:基类与派生类的概念和实践

访客 技术 2026年8月30日 1
普通类示例

下面先定义一个普通类 Person,包含姓名与状态信息。

// Person.h
#ifndef PERSON_H
#define PERSON_H

#include <string>

class Person
{
private:
    std::string m_first;
    std::string m_last;
    bool m_active;
public:
    Person(const std::string& f = "none",
           const std::string& l = "none",
           bool a = false);
    void show() const;
    bool isActive() const { return m_active; }
    void setActive(bool v) { m_active = v; }
};

#endif
// Person.cpp
#include <iostream>
#include "Person.h"

Person::Person(const std::string& f,
               const std::string& l,
               bool a)
    : m_first(f), m_last(l), m_active(a) {}

void Person::show() const
{
    std::cout << m_last << ", " << m_first;
}
// main.cpp
#include <iostream>
#include "Person.h"

int main()
{
    Person p1("Chuck", "Blizzard", true);
    Person p2("Tara", "Boomdea", false);

    p1.show();
    std::cout << (p1.isActive() ? ": 已激活" : ": 未激活") << '\n';

    p2.show();
    std::cout << (p2.isActive() ? ": 已激活" : ": 未激活") << '\n';

    return 0;
}

继承关系

从一个已有的类派生出新类时,原来的类称为基类,新生成的类称为派生类。下面以 Player 为基类,RankedPlayer 为派生类说明。

访问控制

  • public 成员:任意地方都可以访问。
  • protected 成员:只能在类本身及其派生类中访问。
  • private 成员:只能在当前类内部访问,派生类不能直接访问。

公有继承示例

// Player.h
#ifndef PLAYER_H
#define PLAYER_H

#include <string>

class Player
{
private:
    std::string m_first;
    std::string m_last;
    bool m_hasTable;
public:
    Player(const std::string& f = "none",
           const std::string& l = "none",
           bool t = false);
    void display() const;
    bool hasTable() const { return m_hasTable; }
    void setTable(bool v) { m_hasTable = v; }
};

class RankedPlayer : public Player
{
private:
    unsigned int m_score;
public:
    RankedPlayer(unsigned int s = 0,
                 const std::string& f = "none",
                 const std::string& l = "none",
                 bool t = false);
    RankedPlayer(unsigned int s, const Player& p);
    unsigned int score() const { return m_score; }
    void setScore(unsigned int s) { m_score = s; }
};

#endif
// Player.cpp
#include <iostream>
#include "Player.h"

Player::Player(const std::string& f,
               const std::string& l,
               bool t)
    : m_first(f), m_last(l), m_hasTable(t) {}

void Player::display() const
{
    std::cout << m_last << ", " << m_first;
}

RankedPlayer::RankedPlayer(unsigned int s,
                           const std::string& f,
                           const std::string& l,
                           bool t)
    : Player(f, l, t), m_score(s) {}

RankedPlayer::RankedPlayer(unsigned int s, const Player& p)
    : Player(p), m_score(s) {}
// main.cpp
#include <iostream>
#include "Player.h"

int main()
{
    Player p("Tara", "Boomdea", false);
    RankedPlayer rp(1212, p);

    std::cout << "姓名:";
    rp.display();

    std::cout << "\n是否有桌:" << (rp.hasTable() ? "是" : "否")
              << "\n积分:" << rp.score() << '\n';

    return 0;
}

派生类构造函数

派生类对象的构造顺序是:先调用基类构造函数,再执行派生类构造。若不在成员初始化列表中显式调用基类构造函数,编译器会尝试调用基类的默认构造函数。因此,除非想使用默认构造,否则应在初始化列表中显式指定。

// 显式调用基类构造函数
RankedPlayer::RankedPlayer(unsigned int s,
                           const std::string& f,
                           const std::string& l,
                           bool t)
    : Player(f, l, t), m_score(s) {}

下面的写法则会先调用 Player() 默认构造,再用参数构造基类部分的效果将丢失,通常不是期望行为。

// 不推荐:基类部分使用默认构造
RankedPlayer::RankedPlayer(unsigned int s,
                           const std::string& f,
                           const std::string& l,
                           bool t)
{
    m_score = s;
}

继承方式

C++ 支持三种继承方式,最常见的是 public 继承:

  • public 继承:基类的 public 成员在派生类中仍是 public,protected 成员仍是 protected。
  • protected 继承:基类的 public 和 protected 成员在派生类中变为 protected。
  • private 继承:基类的 public 和 protected 成员在派生类中变为 private;class 默认继承方式为 private。

派生类虽然包含了基类的私有成员,但无法直接访问它们,必须通过基类提供的 public 或 protected 接口操作。

]]>

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。