面向对象相关

1、面向对象与面向过程的区别是什么?

面向过程

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

可以拿生活中的实例来理解面向过程与面向对象,例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用不同的方法来实现。

面向对象

面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。

可以明显地看出,面向过程是以事件为中心的开发方法,面向对象是以功能来划分问题,而不是步骤。同样是绘制棋局,这样的行为在面向过程的设计中分散在了多个步骤中,很可能出现不同的绘制版本,因为通常设计人员会考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一。

2、面向对象三大特征?

面向对象方法首先对需求进行合理分层,然后构建相对独立的业务模块,最后通过整合各模块,达到高内聚,低耦合的效果,从而满足用户要求。具体而言,有三个特征:封装、继承和多态。


封装:

封装是指将客观事物抽象成类,每个类对自身的数据和方法进行保护。类可以把自己的数据和方法只让可信的对象操作,对不可信进行信息隐藏。C++中类是一种封装手段,描述客观事物的过程是封装,本质上是对客观事物的抽象。

继承:

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

继承概念的实现方式有三类:实现继承、接口继承和可视继承。

  • 实现继承是指使用基类的属性和方法而无需额外编码的能力;
  • 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
  • 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。
多态

多态是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。

3、面向对象五大原则?

单一职责原则SRP(Single Responsibility Principle)

是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。

开放封闭原则OCP(Open-Close Principle)

一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如:一个网络模块,原来只服务端功能,而现在要加入客户端功能,
那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将服务端和客户端分开,公共部分抽象出来。

替换原则(the Liskov Substitution Principle LSP)

子类应当可以替换父类并出现在父类能够出现的任何地方。比如:公司搞年度晚会,所有员工可以参加抽奖,那么不管是老员工还是新员工,
也不管是总部员工还是外派员工,都应当可以参加抽奖,否则这公司就不和谐了。

依赖原则(the Dependency Inversion Principle DIP)

具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,这个时候,B不应当直接使用A中的具体类: 而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口:这样就达到了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。

通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能造成循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件,而编译B时同样要直接包含到A的cpp文件。

接口分离原则(the Interface Segregation Principle ISP)

模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来

4、什么是深拷贝和浅拷贝?

如果一个类拥有资源(堆或者是其他系统资源),当这个类的对象发生复制时,资源重新分配,这个过程就是深拷贝;反之对象存在资源,但复制过程并未复制资源的情况称为浅拷贝。

程序中,应避免浅拷贝,否则容易导致对同一资源的多次释放。

5、类成员变量的初始化顺序与声明顺序相同吗?

在C++中,类的成员变量的初始化顺序只与变量在类中的声明顺序有关,与构造函数的初始化列表无关。而且静态成员变量先于实例变量,父类成员变量先于自雷成员变量。初始化顺序与变量在内存中的次序有关,而内存中变量的排序,早在编译器就根据变量的定义次序确定了。

6、不能被继承的类如何设计?

将构造函数设为private可以阻止一个类被实例化以及被继承。

方法一:将构造函数设为私有函数。通过共有函数可以向外传递实例。但是所有实例都在堆上,需要程序员手动释放。

  class finalClass1{
  public:
      static finalClass1* get(){
          return new finalClass1;
      }
      static void free(finalClass1* pInstance){
          delete pInstance;
          pInstance = nullptr;
      }
  private:
      finalClass1(){}
      ~finalClass1(){}
  }; 

方法二:由于友元可以访问类的私有成员,可通过友元函数的性质,做如下实现:

  template<typename T> class MakeFinal{
      friend T;
  private:
      MakeFinal(){}
      ~MakeFinal(){}
  };
  class finalClass2:virtual public MakeFinal<finalClass2>{
  public:
      finalClass2(){}
      ~finalClass2(){}
  }

finalClass2是不可继承的类,并且它可以在堆和栈上自由创建。当它继承时,其子类将跳过finalClass2访问MakeFinal的私有构造函数,编译器将报错。

7、多态的分类?

多态分为两种:通用的多态特定的多态。两者的区别是前者对工作的类型不加限制,允许对不同类型的值执行相同的代码;后者只对有限数量的类型有效,而且对不同类型的值可能要执行不同的代码。

通用的多态又分为参数多态(parametric)包含多态(inclusion);特定的多态分为过载多态(overloading)强制多态(coercion)

  • 强制多态
    编译程序通过语义操作,把操作对象的类型强行加以变换,以符合函数或操作符的要求。程序设计语言中基本类型的大多数操作符,在发生不同类型的数据进行混合运算时,编译程序一般都会进行强制多态。程序员也可以显示地进行强制多态的操作(Casting)。
    举个例子,比如,int+double,编译系统一般会把int转换为double,然后执行double+double运算,这个int->double的转换,就实现了强制多态,即可是隐式的,也可显式转换。

  • 过载(overloading)多态
    同一个名(操作符﹑函数名)在不同的上下文中有不同的类型。程序设计语言中基本类型的大多数操作符都是过载多态的。通俗的讲法,就是C++中的函数重载。

  • 参数多态
    采用参数化模板,通过给出不同的类型参数,使得一个结构有多种类型。例如,模板类。

  • 包含多态
    同样的操作可用于一个类型及其子类型(注意是子类型,不是子类)。包含多态一般需要进行运行时的类型检查。例如,虚函数virtual---override机制

8、C++中如何实现多态?

C++中多态是主要通过虚函数实现的。虚函数的本质是通过基类访问派生类定义的函数。每个含虚函数的类,其实例对象内部都有一个虚函数表指针,位于实例首部。该指针被初始化为指向本类虚函数表的内存地址。不管对象类型如何变化,该类对象颞部的虚函数表指针时固定的,因此能够动态地实现多态调用。

9、虚函数使用时注意事项?

仅列举容易出错的几项:

  • 1、声明中virtual关键字即可,在类外不需要,也不能使用virtual关键字。
  • 2、非类成员函数,内联函数、全局函数、类成员函数中静态成员函数和构造函数都不能定义为虚函数。但很有必要将析构函数定义为虚函数,否则delete指向派生类的基类指针时,将只调用基类析构函数,造成内存泄漏。
  • 3、构造函数里可以调用虚函数,由于基类构造函数调用虚函数时,子类还未构造,因此将调用基类自身的版本。子类构造函数中调用虚函数,同样是调用子类自身的版本。
  • 4、使用虚函数需要维护虚函数表,产生额外的系统开销。如果是很小的类,且不需要派生其他类,则没有必要定义虚函数。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容