c++面试常用知识(sizeof计算类的大小,虚拟继承,重载,隐藏,覆盖)

一. sizeof计算结构体

  注:本机机器字长为64位

1.最普通的类和普通的继承

#include<iostream> 
using namespace std;class Parent{
public:void fun(){cout<<"Parent fun"<<endl;}
}; class Child : public Parent{
public:void fun(){cout<<"Child fun"<<endl;}char ch[5];
};int main(){Parent p;Child ch;cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0;
}

/*
  运行结果:
Parent size : 1, Child size : 5
*/

  分析:那么为什么类(对象)的大小为什么会是1个字节呢?那是被编译器插进去的一个char ,使得这个class的不同实体(object)在内存中配置独一无二的地址。也就是说这个char是用来标识类的不同对象的。因为如果不是1,当定义这个类的对象数组时候A objects[5]; objects[0]和objects[1]就在同一个地址处,就无法区分。

2.基类中含有私有成员

 

#include<iostream> 
using namespace std;class Parent{
public:void fun(){cout<<"Parent fun"<<endl;}
private:int x;    
}; class Child : public Parent{
public:void fun(){cout<<"Child fun"<<endl;}char ch[5];
};int main(){Parent p;Child ch;cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0;
}
/*
  执行结果:
  Parent size : 4, Child size : 12
*/

 

  分析:基类里的私有成员在派生类里仍占有内存。在派生类里,基类的int占4个字节,char ch[5]占用5个字节,考虑内存的对齐,变成4+(5+3)=12个字节。

 

3.类中含有虚函数

 

#include<iostream> 
using namespace std;class Parent{
public:virtual void fun(){cout<<"Parent fun"<<endl;}
}; class Child : public Parent{
public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5];
};int main(){Parent p;Child ch;cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0;
}
/*
  执行结果:
  Parent size : 8, Child size : 16
*/

 

  分析:有虚函数的类有个virtual table(虚函数表),里面包含了类的所有虚函数,类中有个virtual table pointers,通常成为vptr指向这个virtual table,占用8个字节的大小。成员类Child public继承于Parent,类Child的虚函数表里实际上有两个虚函数Parent::fun()和Child::hjzgg(),类B的大小等于char ch[5]的大小加上一个指向虚函数表指针vptr的大小,考虑内存对齐为16。一个类里若有虚函数,无论有多少个虚函数都只有一个指向虚表的指针,虚表中的每一个表项保存着一个虚函数的入口地址。当调用虚函数时,先找到虚表中它对应的表项,找到入口地址再执行

4.多重继承

#include<iostream> 
using namespace std;class Parent{
public:virtual void fun(){cout<<"Parent fun"<<endl;}
}; class Father{
public:virtual void fun(){cout<<"Father fun"<<endl;}
};class Child : public Parent, public Father{
public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5];
};int main(){Parent p;Child ch;cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0;
}
/*
  执行结果:
  Parent size : 8, Child size : 24
*/

  分析:Child中除了char ch[5]这5个字节,Child现有一个虚函数表,里边有Child自身定义的虚函数以及从Parent中继承过来的虚函数,然后又另一张虚函数表来存放Father中过来的虚函数,也就是Child对应两个虚函数表的指针。总共内存空间5+8+8=21,考虑内存的对齐,为24字节。

 5.虚继承

  C++虚拟继承

  ◇概念:

     C++使用虚拟继承(Virtual Inheritance),解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。          这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。

  ◇解决问题:

  解决了二义性问题,也节省了内存,避免了数据不一致的问题。 
 同义词: 
  虚基类(把一个动词当成一个名词而已)
  当在多条继承路径上有一个公共的基类,在这些路径中的某几条汇合处,这个公共的基类就会产生多个实例(或多个副本),若只想保存这个基类的一个实例,可以将这个   公共基类说明为虚基类。

  ◇执行顺序

     首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;

   执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;

   执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造;

   执行派生类自己的构造函数;

     析构以与构造相反的顺序执行;

  注:

    从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生类的构造函数调用虚基类           的构造函数而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次。

    在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。

 5.1 没有用虚拟继承

#include<iostream> 
using namespace std;class Parent{
public:virtual void fun(){cout<<"Parent fun"<<endl;}
}; class Father{
public:virtual void fun(){cout<<"Father fun"<<endl;}
};class Child : public Parent, public Father{
public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5];
};int main(){Parent p;Child ch;ch.fun();

    ch.Parent::fun();//这样调用是对的
    ch.Father::fun();

    cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0;
}
/*
  执行结果:
[Error] request for member 'fun' is ambiguous
*/


    分析:因为派生类中的虚函数表会继承来自各个基类的虚函数。所以Child对应的虚函数表中会有Parent 和 Father各自的fun()函数,所以在调用的时候就会出现歧义,不知道应该调用哪个!

  同样,和下面一样的写法也是错误的,增加一个Super类。

#include<iostream> 
using namespace std;class Super{
public:virtual void fun(){cout<<"Super fun"<<endl;}
};class Parent :  public Super{
public:}; class Father : public Super{
public:};class Child : public Parent, public Father{
public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5];
};int main(){Parent p;Child ch;ch.fun();cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;return 0;
}
/*
  执行结果:
[Error] request for member 'fun' is ambiguous
*/

 5.2 使用虚拟继承#include<iostream> 

using namespace std;class Super{
public:Super(){cout<<"Super construction"<<endl;}virtual void fun(){cout<<"Super fun"<<endl;}
};class Parent : virtual public Super{
public:Parent(){cout<<"Parent construction"<<endl;}
}; class Father : virtual public Super{
public:Father(){cout<<"Father construction"<<endl;}
};class Child : public Parent, public Father{
public:virtual void hjzgg(){cout<<"呵呵"<<endl;}char ch[5];
};int main(){Child ch;ch.fun();cout<<"Parent size : "<<sizeof(Parent)<<", Child size : "<<sizeof(Child) <<endl;return 0;
}
/*
  执行结果:
  

   Super construction
   Parent construction
   Father construction
   Super fun
   Parent size : 8, Child size : 24


*/

  分析:

  1.在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。
  2.声明了虚基类之后,虚基类在进一步派生过程中始终和派生类一起,维护同一个基类子对象的拷贝。(Super的构造函数只执行了一次,如果不是有虚基类,那么Super的构造函数     将会执行两次。)
  3.观察类构造函数的构造顺序,拷贝也只有一份。

二. c++重载、覆盖、隐藏的区别和执行方式

  1.成员函数被重载的特征
  (1)相同的范围(在同一个类中); 
  (2)函数名字相同; 
  (3)参数不同; 
  (4)virtual 关键字可有可无。 
  2.“覆盖”是指派生类函数覆盖基类函数,特征是:
  (1)不同的范围(分别位于派生类与基类); 
  (2)函数名字相同; 
  (3)参数相同; 
  (4)基类函数必须有virtual 关键字。 
  3.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,特征是:

  (1)不同的范围(分别位于派生类与基类);

  (2)如果派生类的函数与基类的函数同名,但是参数不同,此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。 
  (3)如果派生类的函数与基类的函数同名,且参数相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

  小结:说白了就是如果派生类和基类的函数名和参数都相同,属于覆盖,这是可以理解的吧,完全一样当然要覆盖了;如果只是函数名相同,参数并不相同,则属 于隐藏。

转载于:https://www.cnblogs.com/hujunzheng/p/4948421.html

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

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

相关文章

嵌入式面试题(一)

目录1 关键字volatile有什么含义&#xff1f;并给出三个不同的例子2. c和c中的struct有什么不同&#xff1f;3.进程和线程区别4.ARM流水线5.使用断言6 .嵌入式系统的定义7 局部变量能否和全局变量重名&#xff1f;8 如何引用一个已经定义过的全局变量&#xff1f;9、全局变量可…

能ping通ip但无法ping通域名和localhost //ping: bad address 'www.baidu.com'

错误描述&#xff1a; ~ # ping localhost ping: bad address localhost原因&#xff0c;在/etc目录下缺少hosts文件&#xff0c;将linux中的/etc hosts文件拷入即可 ~ # ping localhost PING localhost (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: seq0 ttl64 tim…

eclipse导入web项目之后项目中出现小红叉解决办法

项目中有小红叉我遇到的最常见的情况&#xff1a; 1、项目代码本身有问题。&#xff08;这个就不说了&#xff0c;解决错误就OK&#xff09; 2、项目中的jar包丢失。&#xff08;有时候eclipse打开时会出现jar包丢失的情况&#xff0c;关闭eclipse重新打开或者重新引入jar包就O…

arm开发板通过网线连接笔记本电脑上外网

需要工具&#xff1a;arm开发板&#xff0c;网线&#xff0c;一台双网卡的win7笔记本电脑&#xff08;笔记本电脑一般都是双网卡&#xff09; 一、笔记本电脑需要先连上外网&#xff0c;可以连上家里的WIFI&#xff0c;或者手机开热点&#xff08;本人未测试过连接手机的热点&…

windows下实现Git在局域网使用

1.首先在主机A上创建一个文件夹用于存放你要公开的版本库。然后进入这个文件夹&#xff0c;右键->Git create repository here&#xff0c;弹出的窗口中勾选Make it Bare&#xff01;之后将这个文件夹完全共享&#xff08;共享都会吧&#xff1f;注意权限要让使用这个文件夹…

解决linux下QtCreator无法输入中文的情况

安装了QtCreator(Qt5.3.1自带版本)后无法输入中文&#xff0c;确切的说是无法打开输入法。以前使用iBus输入法的时候没有这个问题&#xff0c;现在使用sougou输入法才有的这个问题。 可以查看此文 http://www.cnblogs.com/oloroso/p/5114041.html 原因 有问题就得找原因&…

lintcode 滑动窗口的最大值(双端队列)

题目链接&#xff1a;http://www.lintcode.com/zh-cn/problem/sliding-window-maximum/# 滑动窗口的最大值 给出一个可能包含重复的整数数组&#xff0c;和一个大小为 k 的滑动窗口, 从左到右在数组中滑动这个窗口&#xff0c;找到数组中每个窗口内的最大值。 样例 给出数组 [1…

你的main函数规范吗?

在学习c语言的时候&#xff0c;有一个函数一直被我们使用&#xff0c;那就是main函数&#xff0c;但是你知道标准里面是怎么规定它的写法吗&#xff1f; 平时看见的main函数有下面这几种&#xff1a; 1.int main(void){ }2.int main(){ }3.int main(int argc, char *argv[])…

lintcode 最长上升连续子序列 II(二维最长上升连续序列)

题目链接&#xff1a;http://www.lintcode.com/zh-cn/problem/longest-increasing-continuous-subsequence-ii/ 最长上升连续子序列 II 给定一个整数矩阵&#xff08;其中&#xff0c;有 n 行&#xff0c; m 列&#xff09;&#xff0c;请找出矩阵中的最长上升连续子序列。&a…

适用于Linux的Windows子系统WSL

以前使用的都是在虚拟机里安装linux&#xff0c;最近才发现在win10提供了WSL(Windows Subsystem for Linux) &#xff0c;简单来说就是可以在win10里面直接使用Linux。 &#xff08;一&#xff09;首先打开Microsoft Store , 搜索 Linux &#xff08;二&#xff09;选择自己需…

jsp通过易宝方式实现在线支付

项目下载地址: https://github.com/hjzgg/OnlinePayment 参考&#xff1a;http://blog.csdn.net/jadyer/article/details/7380259?utm_sourcetuicool&utm_mediumreferral 效果图1&#xff1a;请求界面 效果图2&#xff1a;地支付请求和易宝之间建立连接之后跳转到相应的银…

permission denied是什么鬼?

问题&#xff1a;在PC端编译了一个arm芯片的测试程序&#xff0c;出现了permission denied 解决办法&#xff1a; 1.给文件赋予可执行权限 chmod ax xxx这是一般第一反应会想到的答案 2. 有时候已经有可执行权限&#xff0c;还是提示上面的错误此时要注意你的交叉编译器是否正…

CSS中div覆盖另一个div

将一个div覆盖在另一个div上有两种手段&#xff1a;一是设置margin为负值&#xff0c;二是设置绝对定位。 可以根个人情况设置z-index的值 1->position 为absolute的情况 <html> <head> <style> #div1{position:absolute;width:300px;height:300px;backgr…

nand flash和nor flash的这几点区别你知道吗?

这篇文章讲解nand flash和nor flash的特点和区别&#xff0c;不涉及存储原理的讲解 &#xff08;一&#xff09;Flash简介 FLASH是一种存储芯片&#xff0c;全名叫Flash EEPROM Memory&#xff0c;通地过程序可以修改数据&#xff0c;即平时所说的“闪存”。Flash又分为NAND f…

c++堆

c reference: http://www.cplusplus.com/reference/algorithm/make_heap/ heap并不属于STL容器组件&#xff0c;它分为 max heap 和min heap&#xff0c;在缺省情况下&#xff0c;max-heap是优先队列&#xff08;priority queue&#xff09;的底层实现机制。 而这个实现机制中的…

关于Ubuntu拒绝root用户ssh远程登录

今天使用SecureCRT远程登陆Ubuntu时一直提示密码或用户名错误&#xff0c;实际输入是正确的&#xff0c;我按照网上教程改还是不行&#xff0c;后来才想起来我是root登录的&#xff0c;Ubuntu默认的ssh远程root登录是关闭的&#xff0c;在这里记录一下 1.编辑配置文件 #sudo v…

windows8建立局域网的方法

win8建立局域网的方法&#xff1a;1、首先笔记本有无线网卡且支持 虚拟WIFI ;2、按winX键&#xff0c;选择"命令提示符(管理员)A"; 3、输入"netsh wlan set hostednetwork modeallow ssid网络名称 key我的密码" ; 4、接着输入"netsh wlan start hoste…

内核移植出现:Kernel panic - not syncing: No init found.

今天在升级SDK的时候&#xff0c;升级到kernel时遇到如题所述的问题&#xff0c;花了天时间调通&#xff0c;在这里记录一下。 报错提示&#xff1a;(当时没有记录&#xff0c;错误的提示大概如下) Kernel panic - not syncing: No init found. Try passing init option to k…

lintcode Permutation Index

题目&#xff1a;http://www.lintcode.com/zh-cn/problem/permutation-index/ 排列序号 给出一个不含重复数字的排列&#xff0c;求这些数字的所有排列按字典序排序后该排列的编号。其中&#xff0c;编号从1开始。 样例 例如&#xff0c;排列[1,2,4]是第1个排列。 思路&#xf…

32位和64位机器上C语言数据类型的大小

作为嵌入式开发的人员&#xff0c;是必须了解C语言在不同位数机器上占用的字节大小的&#xff0c;下面做下对比 不同位数平台对比&#xff1a; \16位平台32位平台64位平台char1个字节8位1个字节8位1个字节short2个字节16位2个字节16位2个字节int2个字节16位4个字节32位 4个字节…