【C++ Priemr | 15】面向对象程序设计

类型准换与继承

为了支持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++如何防止一个类被其他类继承

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

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

相关文章

linux里source、. 、sh、bash、./有什么区别

转载&#xff1a;https://www.cnblogs.com/pcat/p/5467188.html 1.source a.sh source可以简写为“.”&#xff0c;即. a.sh 注意中间有空格&#xff0c;在当前shell内去读取、执行a.sh&#xff0c;而a.sh不需要有"执行权限"。 2.sh a.sh 和 bash a.sh 都是打开…

【C++ Priemr | 15】虚函数表剖析(三)

一、虚拟菱形继承 #include <iostream> using namespace std;class B { public:int _b; };class C1 :virtual public B { public:int _c1; };class C2 :virtual public B { public:int _c2; };class D :public C1, public C2 { public:int _d; };int main() {cout <&…

gcc的警告提示信息

gcc包含完整的出错检查和警告提示功能。采用-pedantic选项&#xff0c;对于不符合ANSI/ISO标准的源代码会产生相应的警告信息。如&#xff1a;gcc -pedantic hello.c -o hello (main函数返回类型为int&#xff0c;且函数体内要有return 语句&#xff0c;一般为 return 0;) -pe…

1037. 在霍格沃茨找零钱(20)

如果你是哈利波特迷&#xff0c;你会知道魔法世界有它自己的货币系统 —— 就如海格告诉哈利的&#xff1a;“十七个银西可(Sickle)兑一个加隆(Galleon)&#xff0c;二十九个纳特(Knut)兑一个西可&#xff0c;很容易。”现在&#xff0c;给定哈利应付的价钱P和他实付的钱A&…

【Leetcode | 6】136. 只出现一次的数字

给定一个非空整数数组&#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 说明&#xff1a; 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗&#xff1f; 示例 1: 输入: [2,2,1] 输出: 1 示例 2: 输入…

gcc的优化功能

代码优化的目的是改善程序的执行性能。gcc提供的代码优化功能非常强大&#xff0c;它通过参数-On来控制优化代码的生成&#xff0c;其中n为优化级别的整数&#xff0c;比较典型的范围是从0变化到2或3&#xff08;与版本有关&#xff09;。 编译时通过使用选项-O可以告诉gcc同时…

gcc编译多个源代码文件的过程(引出makefile)

由foo1.c foo2.c foo3.c 3个源文件组成的源程序生成最终的可执行程序foo的命令&#xff1a; gcc foo1.c foo2.c foo3.c -o foo 如果处理的源文件不止一个&#xff0c;则gcc会依次对每个文件进行预处理、编译、汇编&#xff0c;最后将所有的目标代码和库文件进行&#xff0c;链…

观擦者模式

/********************************************************************created: 2006/07/20filename: Observer.hauthor: 李创http://www.cppblog.com/converse/purpose: Observer模式的演示代码 *********************************************************************/…

程序的装入和链接

注&#xff1a;这是本人学习汤小丹等编写的计算机操作系统&#xff08;西安电子科技大学出版社&#xff09;的学习笔记&#xff0c;因此许多引用来源于此书&#xff0c;在正文中就不注明了&#xff01; 程序在运行前需要经过以下步骤&#xff1a;编译程序对源程序进行编译生成…

内存对齐

1. 对齐原则&#xff1a; 数据成员对齐规则&#xff1a;结构(struct)(或联合(union))的数据成员&#xff0c;第一个数据成员放在offset为0的地方&#xff0c;以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中&#xff0c;比较小的那个进行。结构(或…

1006. 换个格式输出整数 (15)

让我们用字母B来表示“百”、字母S表示“十”&#xff0c;用“12...n”来表示个位数字n&#xff08;<10&#xff09;&#xff0c;换个格式来输出任一个不超过3位的正整数。例如234应该被输出为BBSSS1234&#xff0c;因为它有2个“百”、3个“十”、以及个位的4。 输入格式&a…

静态库的制作和使用

Linux下的静态库为lib*.a格式的二进制文件&#xff08;目标文件&#xff09;&#xff0c;对应于Windows下的.lib格式的文件。 &#xff08;1&#xff09;命名规则 lib库名字 .a libMytest.a &#xff0c;则库名字为mytest。下面以具体的代码为例介绍如何制作静态库。 //mai…

IO多路复用之select

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout); 分析&#xff1a; nfds: 监控的文件描述符集里最大文件描述符加1&#xff0c;因为此参数会告诉内核检测前多少个文件描述符的状态 readfds&#xff1a; …

1031. 查验身份证(15)

一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下&#xff1a; 首先对前17位数字加权求和&#xff0c;权重分配为&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&#xff0c;8&#xff0c;4&#xff0c;2&#xff0c;1&…

虚拟地址空间

对于每一个进程都会对应一个虚拟地址空间&#xff0c;对于32位的操作系统&#xff08;其指令的位数最大为32位&#xff0c;因此地址码最多32位&#xff09;&#xff0c;虚拟地址空间的大小为B即0~4GB的虚拟地址空间&#xff0c;其中内核空间为1GB&#xff0c;如下所示&#xff…

Leecode 69. x 的平方根

实现 int sqrt(int x) 函数。 计算并返回 x 的平方根&#xff0c;其中 x 是非负整数。 由于返回类型是整数&#xff0c;结果只保留整数的部分&#xff0c;小数部分将被舍去。 示例 1: 输入: 4 输出: 2 示例 2: 输入: 8 输出: 2 说明: 8 的平方根是 2.82842..., 由于返回类…

1002. 写出这个数 (20)

读入一个自然数n&#xff0c;计算其各位数字之和&#xff0c;用汉语拼音写出和的每一位数字。 输入格式&#xff1a;每个测试输入包含1个测试用例&#xff0c;即给出自然数n的值。这里保证n小于10100。 输出格式&#xff1a;在一行内输出n的各位数字之和的每一位&#xff0c;拼…

C/C++中NULL指针

先谈一下C/C的强制类型转换Type cast。与强制类型转换相对应的是自动类型转换。或者强制类型转换叫显示类型转换&#xff0c;自动类型转换叫隐式类型转换。自动类型转换会在赋值运算、混合运算、参数传递、返回函数返回值、格式化输出时且当类型出现不一致时发生&#xff0c;转…

1009. 说反话 (20)

给定一句英语&#xff0c;要求你编写程序&#xff0c;将句中所有单词的顺序颠倒输出。 输入格式&#xff1a;测试输入包含一个测试用例&#xff0c;在一行内给出总长度不超过80的字符串。字符串由若干单词和若干空格组成&#xff0c;其中单词是由英文字母&#xff08;大小写有区…

动态库(共享库)的制作和使用

Linux下的动态库为lib*.so格式的二进制文件&#xff08;目标文件&#xff09;&#xff0c;对应于Windows下的.dll格式的文件。 &#xff08;1&#xff09;命名规则 lib库名.so &#xff08;2&#xff09;动态库的制作 1&#xff09;生成与位置无关的代码&#xff08;.o&…