闲聊C++与面向对象思想

艾伦·凯曾说,“I made up the term object-oriented, and I can tell you I did not have C++ in mind.”(“我发明了术语‘面向对象’,可以告诉您我没有C++”)。

今天看到这句话,激发了笔者写一篇文章聊聊C++与面向对象思想的关系。

正统的面向对象思想

艾伦·凯(Alan Kay)是计算机科学家,是面向对象编程(Object-Oriented Programming,简称OOP)的发明者。他在1960年代和1970年代的工作对个人计算机和现代编程概念产生了深远影响。

艾伦·凯对面向对象编程的理解强调以下几个核心概念:

  1. 封装:对象应该将其状态和行为封装起来,隐藏内部实现的细节,只暴露有限的接口与外界交互。而C++提供friend等机制破坏了内部的隐藏。

  2. 消息传递:对象之间的交互应该通过发送消息来完成,而C++将这些消息理解成调用其他对象的方法。

  3. 动态绑定:系统在运行时决定哪个代码将被执行,而不是像C++这样在编译时固定下来。

  4. 原型继承:对象可以通过克隆现有的对象(原型)来创建新对象,并可能在此基础上进行修改,这与C++基于类的继承是不同的。

因此,艾伦·凯的这句话认为C++并没有完全捕捉到他最初提出的面向对象编程的精神和概念。他所提倡的面向对象编程理念更侧重于高层次的抽象和设计原则,而不仅仅是语言特性的集合。
Alan Kay认为在OOP中消息传递比对象更重要,而现在人们往往度强调对象本身的概念
从这个角度来看,“面向对象”思想应该叫“面向消息”思想。

C++在面向对象设计上的弯路

C++“独辟蹊径”的面向对象设计,也走了一些弯路。例如C++是一第一个支持多重继承的编程语言,它允许一个类继承自多个基类。然而,多重继承引入了一些设计上的复杂性和困难,其中最著名的就是“菱形继承”问题。

菱形继承(Diamond Inheritance)

菱形继承是当两个派生类继承自同一个基类,而另一个类又从这两个派生类继承时出现的结构。在这种情况下,最底部的派生类将通过两条不同的路径继承顶部基类的属性和方法,这可能会导致多个副本的出现,以及不确定性和冗余。

   A/ \B   C\ /D

在这个菱形结构中,如果类A定义了一个方法或属性,类B和类C都会继承它,而类D则会从两个路径继承相同的方法或属性。如果类A中的方法或属性不是静态的,那么在类D的对象中就会存在两份相同的方法或属性,这会导致歧义,因为编译器或运行时不知道应该使用哪一个。

虚继承(Virtual Inheritance)

为了解决菱形继承问题,C++引入了虚继承的概念。通过将基类声明为虚拟(virtual)继承,C++确保在继承层次结构中只有一个基类的实例。

虚继承通过引入一个间接层来管理对共享基类的访问,确保即使基类通过多个路径被继承,派生类也只有一份基类的成员。虽然这解决了菱形继承带来的问题,但它也引入了新的复杂性:

  1. 性能开销:虚继承可能会增加额外的运行时开销,因为它需要间接访问基类成员。

  2. 设计复杂性:虚继承使得类的设计和维护变得更加复杂,因为它增加了类之间关系的复杂度。

  3. 初始化复杂性:在虚继承的情况下,初始化共享基类的责任通常落在最派生的类上,这可能导致初始化顺序的问题。

由于这些问题,虚继承通常被认为是C++中一个复杂且难以正确使用的特性。事实上,许多面向对象设计原则和模式都是为了避免使用多重继承和虚继承而提出的。

总之,C++中的多重继承、菱形继承问题以及虚继承的解决方案,反映了C++在实现面向对象概念时遇到的一些设计挑战。这些挑战给后来许多语言带来启示,大部分语言如Java、C#等选择不支持多重继承。

为什么C++不采用正统的面向对象思想设计

C++最初的的设计目标是在C语言的基础上添加面向对象编程的特性,同时保持与C的兼容性以及C的性能优势。C++对面向对象的采用受到其C语言血统的影响,这种影响体现在以下几个方面:

  1. 性能优先:C语言是为了系统级编程而设计的,强调对内存和处理器效率的精细控制,这些特性直接影响了C++的设计。C++保留了这种对性能的追求,这意味着在实现面向对象特性时,需要平衡语言的高层抽象和底层效率。

  2. 兼容性:C++的设计强调与C的向后兼容性。因此,C++程序员可以在面向对象的C++代码中使用纯C代码。这种兼容性是C++广泛采用的一个原因,但它也限制了C++在实现纯面向对象概念上的自由度。

  3. 直接硬件访问:像C语言一样,C++允许程序员直接操作内存和硬件资源,例如通过指针。虽然这提供了极大的灵活性和控制能力,但它也使得C++的面向对象特性更加复杂,因为它需要在易用性和控制之间找到平衡。

  4. 复杂的特性集合:为了在保持C的性能和兼容性的同时支持面向对象编程,C++引入了类、继承、多态、封装等特性。然而,这些特性与C的过程式特性结合在一起,导致了一个复杂的特性集合,这使得C++的面向对象模型比纯面向对象语言更为复杂。

  5. 编译时与运行时的权衡:C++的很多面向对象特性在编译时就已经确定,比如模板和内联函数。这些特性有利于性能优化,但它们也限制了一些面向对象语言中常见的动态行为,例如Smalltalk和Python等语言支持的运行时类型信息和动态绑定。

总之,C++的面向对象特性与其C语言的血统密切相关。C++需要在保持与C的兼容性和性能优势的同时引入面向对象概念,这导致了一个既包含底层系统编程特性又包含高级面向对象特性的语言。这种设计决策使得C++成为一种功能强大但学习和使用起来相对复杂的语言。在实际应用中,这要求开发者仔细考虑如何最有效地利用C++的多范式特性来设计和实现软件系统。

辩证看待C++与面向对象思想

辩证地看待C++与面向对象思想(OOP)的关系意味着要认识到它们之间的紧密联系,以及C++在实现OOP理念时的优势和局限。

C++的优势:

  1. 多范式支持:C++是一种多范式编程语言,不仅支持面向对象编程,还支持过程式编程、泛型编程等。这种多样性使得C++非常灵活,可以适用于各种不同的编程问题和设计选择。

  2. 系统程序设计:C++保留了C语言高效操作硬件资源的能力,使其成为开发系统软件(如操作系统、游戏引擎、嵌入式系统)的理想选择。OOP提供的封装、继承和多态特性可以帮助构建模块化和可维护的系统软件。

  3. 性能优化:C++提供了与硬件操作几乎一样高效的OOP实现,使得开发者能够在不牺牲性能的情况下应用OOP原则。

C++的局限性:

  1. 复杂性:C++的多范式特性和向后兼容C语言的目标使得语言本身非常复杂。这种复杂性可能使得学习和正确使用C++的OOP特性变得困难。

  2. 不纯粹的OOP实现:一些OOP的理想化特性在C++中并没有完全体现,比如C++中对象的生命周期管理通常需要程序员手工处理,而不是完全自动化。

  3. 安全性和可靠性:C++允许直接访问内存和底层系统资源,这虽然提供了极大的灵活性,但也增加了编写出不安全或者不可靠代码的风险。

辩证看待的观点:

  1. 理解设计决策:了解C++设计中的历史和背景,可以帮助我们理解为什么C++以某种方式实现OOP,以及这些设计决策如何影响实际编程。

  2. 选择正确的工具:C++可能不是所有OOP需求的最佳选择。对于需要更纯粹OOP特性的项目,其他语言如Java或Python可能更合适。相应地,对于需要高性能或系统级访问的项目,C++可能是更好的选择。

  3. 权衡利弊:使用C++时,开发者应该根据具体的项目需求和约束来权衡C++的OOP特性与其它特性之间的利弊,以便做出合适的技术选择。

总的来说,辩证看待C++与OOP的关系要求我们既要理解C++如何支持OOP理念,也要意识到C++实现这些理念的独特方式及其带来的优势和挑战。深入理解C++的优劣和历史,我们可以更有效地使用这个强大但复杂的工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/43452.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搞不清啊?伦敦金与上海金区别是?

进入黄金市场的朋友,有可能会被各式各样的黄金交易品种带得眼花缭乱,其实各品种虽然都以黄金作为投资标的物,但是也是各有不同的,下面我们就来比较一下相似的投资品种——伦敦金和上海金。 首先在比较之前,我们要搞清楚…

基于泰坦尼克号生还数据进行 Spark 分析

基于泰坦尼克号生还数据进行 Spark 分析 在这篇博客中,我们将展示如何使用 Apache Spark 分析著名的泰坦尼克号数据集。通过这篇教程,您将学习如何处理数据、分析乘客的生还情况,并生成有价值的统计信息。 数据解析 • PassengerId &#…

快速排序[原理,C++实现,注意事项,时间复杂度分析]

模板&#xff1a; //本模板来自ACwing void quick_sort(int q[],int l,int r) {if(l>r) return;int xq[lr>>1],il-1,jr1;while(i<j){do i;while(q[i]<x);do j--;while(q[j]>x); if(i<j) swap(q[i],q[j]);}quick_sort(q,l,j);quick_sort(q,j1,r); };原理&…

江苏高防服务器都有哪些优势?

江苏高防服务器所针对的应用群体是不同的&#xff0c;高防服务器与普通服务器的应用效果和功能上是有着很大的差别&#xff0c;所以企业与用户在进行挑选高防服务器时&#xff0c;会更加看重服务器的质量与服务效果&#xff0c;本文就来聊一下江苏高防服务器的优势有哪些吧&…

1509.三次操作后最大值与最小值的最小差

1.题目描述 给你一个数组 nums 。 每次操作你可以选择 nums 中的任意一个元素并将它改成 任意值 。 在 执行最多三次移动后 &#xff0c;返回 nums 中最大值与最小值的最小差值。 示例 1&#xff1a; 输入&#xff1a;nums [5,3,2,4] 输出&#xff1a;0 解释&#xff1a;我们最…

字典操作(获取类操作、添加更新类操作、字典删除类操作)

字典数据获取类操作 keys() 用来获取字典中所有的 key, 保存到一个列表中&#xff0c;并以 dict_keys类型返回 stu {name: Tom, age: 23, gender: male, address: BeiJing} ks stu.keys() print(ks)values() 用来获取字典中所有的 value &#xff0c;保存到一个列表中&#…

注册中心组成结构和基本原理解析

假如你正在设计和开发一个分布式服务系统&#xff0c;系统中存在一批能够独立运行的服务&#xff0c;而在部署上也采用了集群模式以防止出现单点故障。显然&#xff0c;对于一个完整的业务系统而言&#xff0c;这些服务之间需要相互调用并形成复杂的访问链路&#xff0c;一种可…

Casual decoder 和prefix decoder 区别

Causal Decoder&#xff08;因果解码器&#xff09;和Prefix Decoder&#xff08;前缀解码器&#xff09;是两种不同的语言模型架构&#xff0c;它们在处理文本生成任务时采用不同的注意力机制。 Causal Decoder是一种自回归模型&#xff0c;它在生成文本时只能依赖于已经生成…

mysql面试题 Day5

1 什么是事务&#xff1f; 事务是指 多个数据库操作组成一个逻辑执行单元&#xff0c;满足ACID四个条件。 A是指原子性&#xff0c;事务保证操作要么全部完成&#xff0c;要么全部不完成&#xff0c;不会出现部分完成的情况&#xff1b; C是指一致性&#xff0c;事务执行后&…

C++ 定时器触发

c定时器&#xff0c;能够定时触发&#xff0c;即每隔一段固定时间执行一下函数 #include <iostream> #include <thread> #include <chrono> #include <signal.h> #include <time.h> #include <cstring> #include <glog/logging.h>#…

SQL Server解决Float字段使用ISNULL时报错

SQL Server解决Float字段使用ISNULL时报错 一、前言1.报错内容2.解决案例 一、前言 1.报错内容 > [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]从数据类型 varchar 转换为 float 时出错。 (8114)。这个错误通常是由于SQL Server在执行ISNULL函数时遇到…

防抖和节流使用场景

防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;是两种常用的性能优化技术&#xff0c;用于限制某些高频率执行的函数的调用次数&#xff0c;从而优化性能和用户体验。它们的主要区别在于控制函数执行频率的策略不同。 防抖&#xff08;Debounce…

Mini-L-CTF-2022 minispringboot Thymeleaf模板注入 spel的绕过

Mini-L-CTF-2022 minispringboot Thymeleaf模板注入 spel的绕过 就是一个低版本的Thymeleaf注入 漏洞点 public class MainController {GetMapping({"/{language}"})public String test(PathVariable(name "language") String language, RequestParam(…

codesys多段直线电机跨电机控制

1. 电机描述 在X轴上有多段直线电机&#xff0c;如下图有9个&#xff0c;从X1到X9. 2.codesys程序结构 程序名称&#xff1a;Pou_two_motors 动作名称&#xff1a;ACT_move 把这个程序搞到任务配置里面 通过ethercat总线命名一下这些电机&#xff0c;方便调用。 3.程序内容 P…

油烟监测仪:守护厨房,让蓝天白云成为常态

夏日炎炎&#xff0c;白天的酷暑让人们更加向往夜晚的凉爽与惬意。在这样的季节里&#xff0c;品尝各式烧烤、小龙虾&#xff0c;再搭配一杯冰镇啤酒&#xff0c;成为了许多市民夜晚消遣的不二选择。然而&#xff0c;随之而来的餐饮油烟问题也进入了高发阶段&#xff0c;对周边…

智能锁赛博化,凯迪仕携全球顶尖科技亮相建博会!

7月8日&#xff0c;作为大家居建材行业全球规模第一大展&#xff0c;2024中国建博会&#xff08;广州&#xff09;在广交会展馆正式拉开序幕。据官方数据显示&#xff0c;本届展会展出规模展览总规模近40万平方米&#xff0c;建筑装饰领域各细分题材的一线品牌几乎全部参展。 其…

构建安全稳定的应用:SpringSecurity实用指南

以下是关于构建安全稳定的应用&#xff1a;Spring Security 实用指南的详细介绍&#xff1a; 一、Spring Security 概述 Spring Security 是一个功能强大且高度可定制的安全框架&#xff0c;旨在为 Java 应用程序提供全面的安全解决方案。它涵盖了认证&#xff08;Authenticati…

循环练习题

思路&#xff1a; 代码&#xff1a; public static void main(String[] args) {double sum0;for (int i1;i<100;i){if (i%2!0){sum1.0/i;}else {sum-1.0/i;}}System.out.println(sum);} 结果为&#xff1a;

Java 方法中的参数:灵活应用与技巧

Java 方法的参数是在方法定义中声明的变量&#xff0c;用于接收调用者传递的数据。参数可以是基本数据类型&#xff08;如整数、浮点数&#xff09;、对象引用或者特定类型&#xff08;如数组、枚举&#xff09;。方法可以根据参数的类型和数量来执行不同的逻辑&#xff0c;通过…

vscode取消未使用变量的提示(爆红)

目前项目正在使用ts&#xff08;TypeScript&#xff09;&#xff0c;可以在 tsconfig.json 文件中调整编译选项 在你的项目中找到并打开 tsconfig.json 文件&#xff0c;将noUnusedLocals和noUnusedParameters设置为false&#xff0c;关闭vscode重新打开项目即可 {"comp…