类型准换与继承

为了支持c++的多态性,才用了动态绑定和静态绑定。

需要理解四个名词:

  1. 对象的静态类型:对象在声明时采用的类型,是在编译期确定的。
  2. 对象的动态类型:目前所指对象的类型,是在运行期决定的。对象的动态类型可以更改,但是静态类型无法更改。

关于对象的静态类型和动态类型,看一个示例:

class B {}class C : public B {}class D : public B {}D* pD = new D();  // pD的静态类型是它声明的类型D*,动态类型也是D*
B* pB = pD;       // pB的静态类型是它声明的类型B*,动态类型是pB所指向的对象pD的类型D*
C* pC = new C();
pB = pC;          // pB的动态类型是可以更改的,现在它的动态类型是C*

 动态绑定与静态绑定:

  • 静态绑定:又名前期绑定,绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期;
  • 动态绑定:又名后期绑定,绑定的是动态类型,所对应的函数或属性依赖于对象的动态类型,发生在运行期;

比如常见的,virtual函数是动态绑定,non-virtual函数是静态绑定,缺省参数值也是静态绑定。

class B {
public:void DoSomething();virtual void vfun();
}class C : public B {
public: //首先说明一下,这个子类重新定义了父类的no-virtual函数,这是一个不好的设计,会导//致名称遮掩;这里只是为了说明动态绑定和静态绑定才这样使用。 virtual void vfun(); void DoSomething();
}class D : public B {
public:void DoSomething();virtual void vfun();
}D* pD = new D();
B* pB = pD;

【问题】pD->DoSomething() 和 pB->DoSomething() 调用的是同一个函数吗?
不是,虽然pD和pB都指向同一个对象。因为函数DoSomething是一个no-virtual函数,它是静态绑定的,也就是编译器会在编译期根据对象的静态类型来选择函数。pD的静态类型是D*,那么编译器在处理pD->DoSomething()的时候会将它指向D::DoSomething()。同理,pB的静态类型是B*,那pB->DoSomething()调用的就是B::DoSomething()。

【问题】pD->vfun() 和pB->vfun() 调用的是同一个函数吗?
是的,因为vfun是一个虚函数,它动态绑定的,也就是说它绑定的是对象的动态类型,pB和pD虽然静态类型不同,但是他们同时指向一个对象,他们的动态类型是相同的,都是D*,所以,他们的调用的是同一个函数:D::vfun()。

【注意】上面都是针对对象指针的情况,对于引用(reference)的情况同样适用。

指针和引用的动态类型和静态类型可能会不一致,但是对象的动态类型和静态类型是一致的。

当缺省参数和虚函数一起出现的时候情况有点复杂,极易出错。我们知道,虚函数是动态绑定的,但是为了执行效率,缺省参数是静态绑定的。

class B {
public:virtual void vfun(int i = 10) { cout << "class B: " << i << endl; }
};class D : public B {
public:virtual void vfun(int i = 20) { cout << "class D: " << i << endl; }
};int main()
{D* pD = new D();B* pB = pD;pD->vfun();pB->vfun();return 0;
}

输出结果:

分析:有上面的分析可知pD->vfun()和pB->vfun()调用都是函数D::vfun(),但是他们的缺省参数是多少?缺省参数是静态绑定的,pD->vfun()时,pD的静态类型是D*,所以它的缺省参数应该是20;同理,pB->vfun()的缺省参数应该是10。编写代码验证了一下,正确。

抽象基类

#include <iostream>
using namespace std;class A {
public: virtual void out1() = 0;virtual ~A() {};virtual void out2() { cout << "A(out2)" << endl; }void out3() { cout << "A(out3)" << endl; }
};class B : public A {
public:virtual ~B() {};void out1(){ cout << "B(out1)" << endl; }void out2(){ cout << "B(out2)" << endl; }void out3(){ cout << "B(out3)" << endl; }
};int main()
{A *ab = new B;ab->out1();ab->out2();ab->out3();cout << "************************" << endl;B *bb = new B;bb->out1();bb->out2();bb->out3();delete ab;delete bb;return 0;
}

输出结果:

c++如何防止一个类被其他类继承?

如何在防止一个类被其他的类继承呢?

如果是仅仅为了达到这个目的可以直接把这个类的构造函数设置成私有的,这样就杜绝了其他类的继承。也相当于毁掉了这个类(无法再创造出自己的对象)。

那么怎么样既要保证这个类的完整性,又防止其他类的继承呢?

这就要借助友元来实现,因为友元是不可以被继承的。如果一个类的构造函数要借助它的友元类,那么继承了这个类的类就无法构造自己的对象。从而杜绝了被继承。

#include <iostream>
using namespace std;
class C;class BASE
{
private:BASE() {}friend class C;    //设class C为class BASE的友元
};
class C : public virtual BASE
{
};
class D :public C
{
};int main()
{C c;//D d;   不可以实例化对象
}

为什么class C要虚拟继承class BASE 而不是直接继承呢?

参考资料

  • c++如何防止一个类被其他类继承

【C++ Priemr | 15】面向对象程序设计相关推荐

  1. 软考中级(软件设计师)——面向对象程序设计(C++Java二选一的题15分-目标3分)

    软考中级(软件设计师)--面向对象程序设计(C++&Java二选一的题15分-目标3分) 目录 软考中级(软件设计师)--面向对象程序设计(C++&Java二选一的题15分-目标3分) ...

  2. C++ primer 第15章 面向对象程序设计

    文章目录 前言 OOP:概述 继承 动态绑定 定义基类和派生类 定义基类 成员函数与继承 访问控制与继承 定义派生类 派生类中的虚函数 派生类对象及派生类向基类的类型转换 派生类构造函数 派生类使用基 ...

  3. 常惠琢 201771010102《面向对象程序设计(java)》第七周学习总结

    实验七 继承附加实验 实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: (2)掌握Object类的常用API用法: (3)掌握ArrayList类用法 ...

  4. java面向对象电子科大版答案_电子科大17秋《面向对象程序设计》在线作业1

    电子科大17秋<面向对象程序设计>在线作业1 ----------------------------------------------------------------------- ...

  5. JavaScript中的面向对象程序设计

    本文内容目录顺序: 1.Object概念讲述: 2.面向对象程序设计特点: 3.JavaScript中类和实例对象的创建: 4.原型概念: 5.原型API: 6.原型对象的具体使用:7.深入理解使用原 ...

  6. java面向对象程序设计第三版耿祥义pdf_java基础知识干货——封装

    很多java初学者,在学到Java面向对象方面的知识点的时候,会觉得这块的知识点真的蛮绕的,一个知识点一个知识点的往外冒,对于初学者来说区分构造器和方法就花费了一整天的时间.现在小编带大家重新过一遍知 ...

  7. 达拉草201771010105《面向对象程序设计(java)》第十六周学习总结

    达拉草201771010105<面向对象程序设计(java)>第十六周学习总结 第一部分:理论知识 1.程序与进程的概念: (1)程序是一段静态的代码,它是应用程序执行的蓝 本. (2)进 ...

  8. java红牛农场答案_Java面向对象程序设计实验指导与习题解答(21世纪高等学校计算机专业实用规划教材)...

    导语 <Java面向对象程序设计实验指导与习题解答>是<Java面向对象程序设计>(作者耿祥义,清华大学出版社出版,2010)的配套实验指导和习题解答,目的是通过一系列实验练习 ...

  9. [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用

    [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用 本节导读:讨论了表达式树的定义和解析之后,我们知道了表达式树就是并非可执行代码,而是将表达式对象化后的数据结构.是 ...

  10. 20145122《Java面向对象程序设计》实验二实验报告

    实验名称: Java面向对象程序设计 实验内容: 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 PSP时间 步骤 ...

最新文章

  1. 如何使用Dev C++调试(debug)c程序
  2. JAVA大数--POJ 1715 大菲波数
  3. LeetCode—213. 打家劫舍 II
  4. 解决http://localhost:3000/favicon.ico 的404 问题(含案例解析)
  5. 三星Galaxy Note 10系列价格曝光:顶配售价要破万
  6. 《Cocos2D-x权威指南》——3.7 容器类
  7. poj 3590 The shuffle Problem——DP+置换
  8. hadoop基础----hadoop理论----Hadoop简介
  9. Python+OpenCV:二维直方图(2D Histograms)
  10. 国家一级计算机考试选择题题库,计算机一级考试选择题题库与答案2016
  11. php zip类,php ZIP压缩类实例步骤详解
  12. MACOS,应用签名后就崩溃?
  13. 【一周头条盘点】中国软件网(2018.9.10~2018.9.14)
  14. Swagger注解传参
  15. CodeForces - 1169D : Neko Performs Cat Furrier Transform(思维)
  16. Linux环境下获取硬盘序列号
  17. 注册表写入二进制数据
  18. 本机无法 正常连接到桌面端Ubuntu虚拟机
  19. Unity3D中,鼠标控制相机视角并且跟随玩家的几种方法(第三人称)的学习整理
  20. 【安卓实验】实验五、广播实验

热门文章

  1. Java里String.split需要注意的用法
  2. 上周热点回顾(7.8-7.14)
  3. IE8给你选择的理由
  4. 关于 C语言的 按位取反 ~
  5. java动态拼接请求_在JavaWeb项目中处理静态文件或动态链接拼接网站地址的最优处理方案...
  6. python 选择多个文件夹_如何同时选择多个文件?
  7. bat java 启动脚本_从bat脚本运行的Java应用程序上的Windows关闭挂钩
  8. 敲代码括号技巧_理解代码块概念,养成良好编程习惯 | 亲子课堂 第 3 课
  9. python polar函数_Python可视化很简单,可是你会吗?python绘制饼图、极线图和气泡图,让我来教教你吧,一文教会!!!...
  10. c语言如何在文件中间插入数据,急求如何将下列C语言程序数据存储到文件中?...