一. 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[];
}; int main(){
Parent p;
Child ch;
cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;
return ;
} /*
  运行结果:
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[];
}; int main(){
Parent p;
Child ch;
cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;
return ;
}
/*
  执行结果:
  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[];
}; int main(){
Parent p;
Child ch;
cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;
return ;
}
/*
  执行结果:
  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[];
}; int main(){
Parent p;
Child ch;
cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;
return ;
}
/*
  执行结果:
  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[];
}; 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 ;
}
/*
  执行结果:
[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[];
}; int main(){
Parent p;
Child ch;
ch.fun();
cout<<"Parent size : "<<sizeof(p)<<", Child size : "<<sizeof(ch) <<endl;
return ;
}
/*
  执行结果:
[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[];
}; int main(){
Child ch;
ch.fun();
cout<<"Parent size : "<<sizeof(Parent)<<", Child size : "<<sizeof(Child) <<endl;
return ;
}
/*
  执行结果:
  

  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 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

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

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

  1. sizeof求类的大小

    用sizeof求类的大小,http://blog.csdn.net/szchtx/article/details/10254007(sizeof浅析(三)——求类的大小),这篇博文给出了非常详尽的举例 ...

  2. MySQL JDBC常用知识,封装工具类,时区问题配置,SQL注入问题

    JDBC JDBC介绍 Sun公司为了简化开发人员的(对数据库的统一)操作,提供了(Java操作数据库的)规范,俗称JDBC,这些规范的由具体由具体的厂商去做 对于开发人员来说,我们只需要掌握JDBC ...

  3. C++ 类的继承、虚拟继承、隐藏、占用空间

    主函数: #include <iostream> #include "test.h" #include "testfuc.h" using name ...

  4. c/c++面试12-18------关与sizeof那些事儿

    12 使用sizeof计算普通变量所占空间大小 (1)不同数据类型所占字节数不同(32位 64位系统不同) int----->4 double----->8 char-------> ...

  5. Java && Python 算法面试常用类以及方法总结

    数据结构 逻辑结构上: 包括集合,线性结构,非线性结构. 存储结构: 顺序存储,链式存储,索引存储,散列存储. Java 常见数据结构 大专栏  Java && Python 算法面试 ...

  6. Unity游戏开发面试基础知识

    面试第一次知识总结: 一.Unity基本操作 1.unity提供哪几种光源? 点光源.平行光.聚光灯.区域光. 2.物体发生碰撞的必要条件什么? 两个物体必须有碰撞体Collider组件,一个物体上必 ...

  7. Java面试必备知识

    JAVA面试必备知识 第一,谈谈final, finally, finalize的区别. 第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可 ...

  8. javascript常用知识点集

    javascript常用知识点集 目录结构 一.jquery源码中常见知识点 二.javascript中原型链常见的知识点 三.常用的方法集知识点 一.jquery源码中常见的知识点 1.string ...

  9. Java常用的加密解密类(对称加密类)

    Java常用的加密解密类 原文转载至:http://blog.csdn.net/wyc_cs/article/details/8793198 原创 2013年04月12日 14:33:35 1704 ...

随机推荐

  1. javaFx:使用弹出对话框 Alert

    javaFx8 自带的对话框非常好用,类似的使用方式如下: /** * 弹出一个通用的确定对话框 * @param p_header 对话框的信息标题 * @param p_message 对话框的信 ...

  2. 腾讯网2016回响中国:华清远见荣获2016年度知名IT培训品牌

    12月1日,由腾讯网主办的“2016回响中国·腾讯网教育年度盛典”上,揭晓了“2016腾讯网教育年度总评榜”榜单.高端IT就业培训专家——华清远见教育集团凭借自身优质的高薪IT就业服务优势成功入围,荣 ...

  3. IDEA+Tomcat+JRebel热部署

    在完成idea工程简单应用后,接下来实现热部署. 简单应用地址:http://wibiline.iteye.com/admin/blogs/2072454 一.安装JRebel插件 1. 在线安装 F ...

  4. poj3250

    //(栈)poj3250将第i头牛能看到多少牛传化为第i头牛能被多少牛看见 /* #include <stdio.h> #include <stack> using names ...

  5. Spring Mvc的入门

    SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的. Spring Web MVC是什么: Sprin ...

  6. python基础之day1

    Python 简介 Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言. Python为我们提供了非常完善的基础代码库,覆盖了 ...

  7. jsp内置对象

      jsp servlet   对象名 类型 使用范围 request HttpServletRequest 请求 浏览器--->服务器 response HttpServletResponse ...

  8. strcpy函数在VS2015无法使用的问题

    一:原因:一般认为是vs准备弃用strcpy的,安全性较低,所以微软提供了strcpy_s来代替 然而,strcpy_s并没有strcpy好用,我们要想继续在VS2015中使用strcpy该怎么办 呢 ...

  9. 有关JVM配置参数含义

    1.参数的含义-vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M-vmargs 说明后面是VM的参数,所以后面的其实都是JV ...

  10. 2016huasacm暑假集训训练五 H - Coins

    题目链接:http://acm.hust.edu.cn/vjudge/contest/126708#problem/H 题意:A有一大堆的硬币,他觉得太重了,想花掉硬币去坐的士:的士司机可以不找零,但 ...