【C++重载操作符与转换】定义基类和派生类
在C面向对象编程中面向对象编程OOP是核心范式之一而基类和派生类作为 OOP 的重要组成部分构建了类之间的层次结构。通过继承机制派生类可以复用基类的属性和行为并在此基础上进行扩展和修改。同时重载操作符与类型转换在基类和派生类的场景下能够进一步增强代码的灵活性和可读性。一、基类与派生类的基本概念1.1 基类的定义基类是派生类的基础它包含了一组通用的属性和方法这些属性和方法可以被派生类继承。在 C 中基类的定义与普通类类似例如我们定义一个表示 “形状” 的基类Shape代码语言javascriptAI代码解释#include iostream class Shape { protected: std::string name; public: Shape(const std::string s) : name(s) {} virtual void draw() const { std::cout Drawing a shape: name std::endl; } };在这个Shape类中name用于表示形状的名称通过protected访问修饰符使得派生类可以访问该成员变量。draw方法是一个虚函数为后续在派生类中实现多态性奠定了基础。1.2 派生类的定义派生类通过继承基类获取基类的属性和方法并可以添加自己特有的成员或者重写基类的成员函数。派生类的定义语法如下代码语言javascriptAI代码解释class DerivedClass : access - specifier BaseClass { // 派生类的成员声明 };其中access - specifier可以是public、private或protected用于指定基类成员在派生类中的访问权限。例如定义一个Rectangle类作为Shape类的派生类代码语言javascriptAI代码解释class Rectangle : public Shape { private: double width; double height; public: Rectangle(const std::string s, double w, double h) : Shape(s), width(w), height(h) {} void draw() const override { std::cout Drawing a rectangle: name , width: width , height: height std::endl; } double area() const { return width * height; } };在Rectangle类中除了继承Shape类的name和draw方法外还添加了width和height两个私有成员变量以及用于计算面积的area方法并通过重写draw方法实现了特定于矩形的绘制逻辑。二、继承方式与访问权限2.1 公有继承public当派生类使用public继承基类时基类的public成员在派生类中仍然是public的基类的protected成员在派生类中仍然是protected的。意味着在类外部可以通过派生类对象访问基类的public成员而派生类的成员函数和友元函数可以访问基类的protected成员。代码语言javascriptAI代码解释class Circle : public Shape { private: double radius; public: Circle(const std::string s, double r) : Shape(s), radius(r) {} void draw() const override { std::cout Drawing a circle: name , radius: radius std::endl; } double area() const { return 3.14 * radius * radius; } }; int main() { Circle circle(MyCircle, 5.0); circle.draw(); // 可以直接访问基类的 public 方法 return 0; }2.2 私有继承private在私有继承中基类的public和protected成员在派生类中都变为private成员。使得派生类的对象无法在类外部访问基类的任何成员只有派生类的成员函数和友元函数可以访问这些成员。私有继承通常用于实现细节的隐藏不希望基类的接口在派生类外部暴露。代码语言javascriptAI代码解释class PrivateRectangle : private Shape { private: double width; double height; public: PrivateRectangle(const std::string s, double w, double h) : Shape(s), width(w), height(h) {} void draw() const { Shape::draw(); // 在派生类内部访问基类方法 std::cout This is a privately inherited rectangle. std::endl; } }; int main() { PrivateRectangle privRect(PrivateRect, 4.0, 3.0); // privRect.draw(); // 编译错误无法在类外部访问 return 0; }2.3 保护继承protected保护继承时基类的public和protected成员在派生类中都变为protected成员。意味着派生类的对象不能在类外部访问这些成员但派生类的派生类可以访问这些protected成员。保护继承常用于基类的部分接口只希望在继承层次结构中使用的场景。代码语言javascriptAI代码解释class ProtectedCircle : protected Shape { private: double radius; public: ProtectedCircle(const std::string s, double r) : Shape(s), radius(r) {} void draw() const { Shape::draw(); std::cout This is a protectedly inherited circle. std::endl; } }; class SubProtectedCircle : public ProtectedCircle { public: SubProtectedCircle(const std::string s, double r) : ProtectedCircle(s, r) {} void innerDraw() const { draw(); // 可以访问基类的 protected 方法 } };三、重载操作符在基类和派生类中的应用3.1 运算符重载的基本概念运算符重载允许为自定义类型重新定义运算符的行为使得自定义类型的对象可以像内置类型一样使用运算符。例如我们可以重载运算符实现两个矩形的合并操作。代码语言javascriptAI代码解释class Rectangle { private: double width; double height; public: Rectangle(double w 0, double h 0) : width(w), height(h) {} Rectangle operator(const Rectangle other) const { return Rectangle(width other.width, height other.height); } void display() const { std::cout Width: width , Height: height std::endl; } }; int main() { Rectangle rect1(2.0, 3.0); Rectangle rect2(4.0, 5.0); Rectangle result rect1 rect2; result.display(); return 0; }3.2 基类和派生类中运算符重载的特点在基类和派生类的层次结构中运算符重载需要考虑继承关系和多态性。例如当我们在基类中定义了一个运算符重载函数派生类可以重写该函数以实现特定的行为。代码语言javascriptAI代码解释#include iostream class Shape { public: // 添加默认构造函数 Shape() default; virtual Shape* operator(const Shape other) const { std::cout Shape addition operation std::endl; return new Shape(); } // 虚析构函数防止内存泄漏 virtual ~Shape() default; }; class Rectangle : public Shape { private: double width; double height; public: Rectangle(double w 0, double h 0) : width(w), height(h) {} Rectangle* operator(const Shape other) const override { if (const Rectangle* rect dynamic_castconst Rectangle*(other)) { return new Rectangle(width rect-width, height rect-height); } std::cout Unsupported addition operation std::endl; return new Rectangle(); } void display() const { std::cout Width: width , Height: height std::endl; } }; int main() { Rectangle rect1(2.0, 3.0); Rectangle rect2(4.0, 5.0); Rectangle* result rect1 rect2; result-display(); // 手动释放内存 delete result; return 0; }四、类型转换类与内置类型的桥梁4.1 隐式与显式类型转换C提供四种显式类型转换操作符static_cast编译时检查用于明确类型转换如int转double。dynamic_cast运行时检查用于多态类型的向下转型。const_cast移除const或volatile属性需谨慎使用。reinterpret_cast底层二进制转换如指针与整数互转风险高。4.2 用户定义的类型转换通过转换构造函数和类型转换运算符实现类与内置类型的转换。1转换构造函数将内置类型转换为类类型代码语言javascriptAI代码解释#include iostream class SmallInt { private: int val; public: SmallInt(int i) : val(i) {} // 转换构造函数 void print() const { std::cout val std::endl; } }; int main() { SmallInt si 42; // 隐式调用转换构造函数 si.print(); // 输出: 42 return 0; }2类型转换运算符将类类型转换为内置类型代码语言javascriptAI代码解释#include iostream class SmallInt { private: int val; public: SmallInt(int i) : val(i) {} operator int() const { // 类型转换运算符 return val; } }; int main() { SmallInt si(100); int i si; // 隐式调用类型转换运算符 std::cout i std::endl; // 输出: 100 return 0; }3避免隐式转换的歧义使用explicit关键字禁止隐式转换代码语言javascriptAI代码解释#include iostream class SmallInt { private: int val; public: explicit SmallInt(int i) : val(i) {} // 禁止隐式转换 operator int() const { return val; } }; int main() { SmallInt si(100); // int i si; // 错误禁止隐式转换 int i static_castint(si); // 必须显式转换 std::cout i std::endl; // 输出: 100 return 0; }五、类型转换在基类和派生类中的应用5.1 向上转型Upcasting向上转型是将派生类对象转换为基类对象或基类指针 / 引用。这种转换是安全的因为派生类对象包含了基类对象的所有成员。代码语言javascriptAI代码解释#include iostream class Animal { public: virtual ~Animal() default; virtual void speak() const { std::cout Animal sound std::endl; } }; class Dog : public Animal { public: void speak() const override { std::cout Woof! std::endl; } }; int main() { Dog d; Animal* a d; // 向上转型 a-speak(); // 输出: Woof! (多态性) return 0; }5.2 向下转型Downcasting向下转型是将基类指针 / 引用转换为派生类指针 / 引用。由于基类对象可能不是实际的派生类对象因此需要使用dynamic_cast进行安全的向下转型。代码语言javascriptAI代码解释int main() { Animal* a new Dog; // Dog* d a; // 错误不安全 Dog* d dynamic_castDog*(a); // 安全运行时检查 if (d) { d-speak(); // 输出: Woof! } else { cout Invalid cast! endl; } delete a; return 0; }5.3 转换构造函数与类型转换运算符在基类和派生类中也可以使用转换构造函数和类型转换运算符实现类型转换。例如我们可以定义一个从Rectangle到Shape的类型转换运算符。代码语言javascriptAI代码解释#include iostream #include string // 定义 Shape 类 class Shape { private: std::string name; public: Shape(const std::string s) : name(s) {} void draw() const { std::cout Drawing a shape: name std::endl; } }; class Rectangle { private: double width; double height; public: Rectangle(double w 0, double h 0) : width(w), height(h) {} operator Shape() const { return Shape(ConvertedShape); } }; int main() { Rectangle rect(2.0, 3.0); Shape shape rect; shape.draw(); return 0; }六、总结C 中的基类和派生类通过继承机制构建了强大的类层次结构结合重载操作符与类型转换使得代码更加灵活和高效。继承方式决定了基类成员在派生类中的访问权限运算符重载为自定义类型提供了更直观的操作方式而类型转换则在基类和派生类之间架起了桥梁。在实际编程中合理运用这些特性可以提高代码的复用性、可维护性和可扩展性更好地实现复杂的面向对象编程需求。

相关新闻

C++模板树:泛型编程实现通用树形数据结构框架

C++模板树:泛型编程实现通用树形数据结构框架

1. 项目概述:为什么我们需要一个“模版树”?在C的世界里,数据结构是构建一切复杂系统的基石。数组、链表、栈、队列,这些都是我们入门时反复练习的老朋友。但当问题变得复杂,比如你需要管理一个文件系统、组织一个公司…

2026/10/24 11:14:55 阅读更多 →
一次手游上报数据造假的排查记录:从值域校验到服务端重演

一次手游上报数据造假的排查记录:从值域校验到服务端重演

现象 放置类项目,后台监控到离线收益结算异常:一批账号到手的产出明显高于服务端按规则应发的量,且集中在几个高价值道具上。 先看协议层,排除最常见的两种情况。抓包比对上报请求,包签名正确、ts 在窗口内、nonce 无重…

2026/10/25 14:31:13 阅读更多 →
谁在定义视频孪生的下半场?三分天下格局中,镜像视界如何让“展示型”孪生彻底沦为过去式 技术解析白皮书

谁在定义视频孪生的下半场?三分天下格局中,镜像视界如何让“展示型”孪生彻底沦为过去式 技术解析白皮书

编制单位:镜像视界(浙江)科技有限公司 技术依托:国家十四五重点课题专项成果、华东师范大学‑镜像视界浙江普陀时空大数据应用联合研究院联合攻关 目录一、执行摘要 二、行业演进:上半场重展示,下半场重实战…

2026/10/24 0:56:26 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/26 12:00:21 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/27 4:06:49 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/27 7:21:53 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/26 12:00:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/27 6:20:47 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/27 4:06:50 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 12:00:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 7:21:50 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 8:34:37 阅读更多 →