目录树

1.继承

1.1 基类成员在派生类中的访问属性

1.2继承时导致的二义性

1.3 多基继承

2.虚函数的多态

2.1虚函数的定义

2.2派生类中可以根据需要对虚函数进行重定义

2.3 虚函数的访问

2.4哪些函数不能定义为虚函数

2.5虚函数表指针(vptr)和虚基类表指针(bptr)

2.5.1 虚函数表指针vptr

2.5.2含静态变量、虚函数的类的空间计算

2.5.3虚基类表指针

2.5.4 虚拟继承时构造函数的书写

2.5.5虚函数

3.运行时类型识别与显示转换

3.1 typeid

3.2 显式转换

1.继承

如果一个类有多个直接基类,而这些直接基类又有一个共同的基类,则在最底层的派生类中会保留这个间接的共同基类数据成员的多份同名成员。提出虚继承,虚继承时,公共基类在对象模型中只有一份拷贝。

1.1 基类成员在派生类中的访问属性

这里一定要区分清楚派生类对象和派生类中的成员函数对基类的访问时不同的。

1.2继承时导致的二义性

1)在公有继承下(私有,保护继承时,不能隐式转换)下,派生类的对象/对象指针/对象引用可以赋值给基类的对象/对象指针/对象引用(发生隐式转换)。但基类的对象/对象指针/对象引用不能赋值给派生类的对象/对象指针/对象引用。因为派生类包含了基类的所有信息,而基类缺乏派生类中的信息。

2)c++容许把基类的对象指针/对象引用强制转换为(显式)派生类的对象指针/对象引用。

3)一个指向基类的指针可以用来指向该基类公有派生类的任何对象,这是c++实现程序运行时多态性的关键。

1.3 多基继承

当继承基类时,在派生类中就获得了基类所有数据成员的副本,该副本称为子对象。

类mi会包含的的d1的子对象和d2的子对象。如果多个基类中存在同名成员的情况,造成编译器无从判断具体要访问那个基类的成员,则称对基类成员访问的二义性问题。(解决办法:可以加限定符基类)

2.虚函数的多态

多态是面向对象的精髓。可以概括为一个接口,多种方法。通俗来讲,多态是指同一个操作作用于不同的对象就会产生不同的响应。多态性分为静态多态和动态多态。其中的函数重载和运算符重载属于静态多态。虚函数属于动态多态性。c++是通过虚函数实现动态多态的。

2.1虚函数的定义

虚函数的定义是在函数原型前加一个关键字virtual即可。

如果一个基类成员定义为虚函数,那么,他在所有派生类中也保持为虚函数,即使在派生类中省略了virtual关键字,也任然是虚函数。

2.2派生类中可以根据需要对虚函数进行重定义,重定义的格式要求:

1)与基类的虚函数有相同的参数个数;

2)与基类的虚函数有相同的参数类型;

3)与基类的虚函数有相同的返回类型。或者与基类的虚函数相同,或者返回指针(引用),并且派生类虚函数所返回的指针(引用)类型是基类中被替换的虚函数所返回的指针(引用)类型的子类型(派生类型)。

2.3 虚函数的访问

虚函数可以通过对象名访问,此时编译器采用的是静态编译。

1)通过对象名访问虚函数时,调用哪个类的函数取决于定义对象名的类型。对象类型是基类时,就调用基类的函数。对象类型是子类时就调用子类的函数。

2)使用指针访问非虚函数时,编译器根据指针本身的类型决定要访问那个函数,而不是根据指针指向的对象类型。

3)使用指针访问虚函数时,编译器根据指针所指对象的类型决定要访问那个函数,而不是根据指针本身的类型。

4)使用引用访问虚函数,与使用指针访问虚函数类型,不同的是,引用一经声明,引用变量本身无论如何改变其调用的函数都不会改变,始终指向开始定义时的函数。在一定程序上提高了代码的安全性。(受限制的指针)

总结:
c++中函数调用默认不使用动态绑定,要触发动态绑定需满足两个条件:

a.只用指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不能进行动态绑定。

b.必须通过基类类型的引用或指针进行函数调用。

2.4哪些函数不能定义为虚函数

普通函数(类的非成员函数),静态成员函数,构造函数,友员函数。而内联成员函数和赋值操作符重载函数即使声明为虚函数也毫无意义。

2.5虚函数表指针(vptr)和虚基类表指针(bptr)

2.5.1 虚函数表指针vptr

1)每个类产生一堆指向virtual functions 的指针,放在表格中,这个表格称为虚函数表。

2)每个对象被添加一个指针,指向相关的virtual table,通常这个指针被称为vptr(虚函数表指针)vptr的设定和重置由每一个类的构造函数,析构函数和复制构造函数自动完成。每个类所关联的type_info信息(用以支持rtti)也由virtual table 指出。通常放在表格的第一个slot处。

2.5.2含静态变量、虚函数的类的空间计算

sizeof应用在类和结构的处理情况是相同的。但是在类中的静态成员不对结构或类的大小产生影响。

2.5.3虚基类表指针

c++支持单一和多重继承。

class iostream:public istream,public ostream{...};

继承关系也可以指定为虚拟(virtual 共享的意思)

class istream :virtual public ios{...};

class ostream :virtual public ios{...};                  //菱形继承

在虚拟继承中,基类不管在继承串链中被派生多少次,永远只会存在一个实体。

在虚拟继承基类的之类中,子类会增加某种形式的指针,或者指向虚基类子对象,或者指向一个相关的表格,表格中存放的不是虚基类子对象的地址,就是其偏移量。此指针叫bptr.

2.5.4 虚拟继承时构造函数的书写

从A类直接虚拟派生(B和C)和间接派生(D)的类中,其构造函数的初始化列表中都要列出对基类A构造函数的调用。这种机制保障不管有多少层继承,虚基类的构造函数必须且只能被调用一次。

若在初始化列表中没有显式调用虚基类的构造函数,则将调用虚基类的默认构造函数。若虚基类没有定义默认构造函数,则编译错误。

2.5.5虚函数

在基类中不能给出虚函数有意义的实现,而把它声明为纯虚函数,他的实现留给基类的派生类去做。

a.两种常见的抽象类

凡是有纯虚函数 的类叫抽象类(抽象接口),这种类不能声明对象,只是作为基类为派生类服务。除非在派生类中完全实现基类中的所有纯虚函数,否则,派生类也是抽象类,不能实例化对象。

只定义了protected型构造函数的类也是抽象类。对于一个类,如果只定义了protected构造函数而没有提供public构造函数,无论是外部还是派生类中都不能创建该类的对象,但能派生出新类,这种能派生出新类,但不能创建自己对象的类叫另外一种形式的抽象类。

3.运行时类型识别与显示转换

3.1 typeid

c++通过下面两种操作符提供RTTI

1)typeid 操作符,返回指针或引用所指对象的实际类型。

2)dynamic_cast操作符,将基类类型的指针或引用安全的转换为派生类型的指针或引用。

只有当typeid的操作数是带虚函数的类类型的对象时,才返回动态类型信息。

3.2 显式转换

c++中的显式转换也称强制类型转换。包括static_cast、dynamic_cast、 const_cas、 reinterpret_cast。

在引用命名的强制类型转换操作符之前,显式强制类型转换用圆括号将类型括起来实现。

1) reinterpret_cast

int *ip;

char *pc=(char*) ip;

效果与reinterpret_cast相同。

int *ip;

char *pc=reinterpret_cast<char*> ip;

2) const_cast 

除了添加和删除const特性,用const_cast符执行其他任何类型转换都会引起编译错误。

3)static_cast

编译器隐式执行的任何类型转换都可以由static_cast显式完成。

只有当类型之间可隐式转换时(除类层次间的下行转化除外),static_cast的转换才是合法的。否则出错。类层次间的下行转化不能通过隐式转换完成。

使用static_cast完成下行转换(把基类指针或引用转换为子类指针或引用),由于没有动态类型检查,所以不安全。

c++的基本类型的指针之间不含隐式转换(除void*)需要显示转换。故char* 不能隐式转换为int*。

4)dynamic_cast

把expression转换为type类型的对象,type必须是类的指针,类的引用或void*

a.tpye和expression的类型需要一致,都为指针或引用。

与其他转换类型不同,dynamic_cast 涉及运行时类型检查,而这个运行时类型信息存储在类的虚函数表里,只有定义了虚函数的类才有虚函数表,对没有虚函数表的类在使用时会导致dynamic_cast编译错误。如果绑定到引用或指针的对象的类型不是目标类型,则dynamic_cast失败。如果转换到指针类型的dynamic_cast失败,则dynamic_cast的结果为0.如果转换到dynamic_cast失败,则抛出一个bad_cast类型的异常。dynamic_cast操作符执行两个操作。首先验证请求的转换是否有效,操作符执行的验证是在运行时进行的。

b.dynamic_cast主要用于类层次间的上行转换和下行转换

dynamic_cast运算符可以在执行期决定真正的类型。如果下行转换时安全的(基类的指针或引用执行一个派生类对象)这个运算符会传回转型过的指针。如果downcast不安全,这个运算符会传回空指针(基类的指针或引用没有指向一个派生类对象)

在类间进行上行转换时,dynamic_cast和static_cast的效果一样。

在类间进行下行转换时,dynamic_cast具有类型检查功能,比static_cast更加安全。

在运行dynamic_cast时必须包括多态类型。static_cast则没有这个限制。

面向对象编程技术的总结和理解(c++)的更多相关文章

  1. python面向对象编程对象和实例的理解

    给你一个眼神,自己体会

  2. 深入理解Javascript面向对象编程

    深入理解Javascript面向对象编程 阅读目录 一:理解构造函数原型(prototype)机制 二:理解原型域链的概念 三:理解原型继承机制 四:理解使用类继承(继承的更好的方案) 五:建议使用封 ...

  3. JavaScript面向对象编程[转]

    JavaScript面向对象编程 命名空间 命名空间是一个容器,它允许开发人员在一个独特的,特定于应用程序的名称下捆绑所有的功能. 在JavaScript中,命名空间只是另一个包含方法,属性,对象的对 ...

  4. PHP面向对象编程(1)基础

    一.面向对象OOP(Oriented Object Programming) 面向过程的编程 将要实现的功能描述为一个从一开始到结束的连续的“步骤(过程)”. 一次逐步完成这些步骤.如果步骤比较大,又 ...

  5. Java基础教程:面向对象编程[2]

    Java基础教程:面向对象编程[2] 内容大纲 访问修饰符 四种访问修饰符 Java中,可以使用访问控制符来保护对类.变量.方法和构造方法的访问.Java 支持 4 种不同的访问权限. default ...

  6. Java学习之==>面向对象编程 Part2

    一.封装 封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别:将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结 ...

  7. Python设计模式面向对象编程

    前言   本篇文章是基于极客时间王争的<设计模式之美>做的总结和自己的理解.  说到面向对象编程,作为一个合格的Pythoner,可以说信手拈来.毕竟在Python里"万物都是对 ...

  8. 『无为则无心』Python面向对象 — 45、面向对象编程

    目录 1.面向对象编程的概念 2.面向对象编程和面向过程编程的区别 (1)面向过程编程 (2)面向对象编程 3.举例理解面向对象 4.Python的面向对象编程 5.面向对象的几大核心特性 1.面向对 ...

  9. PHP面向对象编程——深入理解方法重载与方法覆盖(多态)

    什么是多态? 多态(Polymorphism)按字面的意思就是“多种状态”.在面向对象语言中,接口的多种不同的实现方式即为多态.引用Charlie Calverts对多态的描述——多态性是允许你将父对 ...

随机推荐

  1. sparkStreaming消费kafka-1.0.1方式:direct方式(存储offset到zookeeper)

    版本声明: kafka:1.0.1 spark:2.1.0 注意:在使用过程中可能会出现servlet版本不兼容的问题,因此在导入maven的pom文件的时候,需要做适当的排除操作 <?xml ...

  2. 实际生产用法CMS和G1

    java -Xms100m -Xmx100m -Xmn50m -XX:MetaspaceSize=20m -XX:MaxMetaspaceSize=20m -XX:+UseConcMarkSweepG ...

  3. tomcat配置介绍

    第一节java的介绍 java需要一个java的运行环境 JDK:包含了好几个java组件,包含类库(API) 开发工具(java) jvm(java虚拟机)JRE(类库) tomcat:开源  企业 ...

  4. 大数据-kafka

    1Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据. 作用:1发布和订阅消息流,这个功能类似于消息队列,这也是kafka归类为消息队列框架的原因 2以容错 ...

  5. Practice| 面向对象

    实参与形参的传递机制 * 实参给形参赋值: * 1.基本数据类型: * 实参给形参的数据值,形参的修改和实参无关 * 2.引用数据类型 * 实参给形参的地址值,如果这个地址值修改“属性”会影响实参,但 ...

  6. 20165319第五周java学习笔记

    教材内容总结 1.String类和StringBuffer类都覆盖了toString方法,都是返回字符串. 所以带不带toString效果是一样的. 2.instanceOf运算符可以用来判断某个对象 ...

  7. Shiro笔记(二)Shiro集成SpringMVC的环境配置

    0.pom文件引入 <!-- SECURITY begin --> <dependency> <groupId>org.apache.shiro</group ...

  8. 反射-Emit

    一.Emit Emit,可以称为发出或者产出.在Framework中,与Emit相关的类基本都存在与System.Reflection,Emit命名空间下.可见Emit是作为反射的一个元素存在,反射可 ...

  9. JSP页面分页显示数据

    效果如上图所示!最多显示10条:完整jsp和后台代码如下: <%@ page contentType="text/html;charset=UTF-8" %> < ...

  10. Web服务API

    Web服务API     内容 [ 隐藏 ]  1 概述 2个 services.php 3 详细教程 4 例子 5 另见 概观 Web服务API允许您将插件的功能(通常是外部函数)公开为Web服务. ...