C++重要知识点小结---2
C++重要知识点小结--1 :http://www.cnblogs.com/heyonggang/p/3246631.html
1.C++允许程序员声明一个不能有实例对象的类,这样的类惟一的用途是被继承。这种类成为抽象类。
一个抽象类至少具有一个纯虚函数。所谓纯虚函数是指被标明为不具体实现的虚成员函数。
如:
virtual void WithDrawal(float amount) = ; //纯虚函数
在WithDrawal()的声明之后的“=0”表明程序员将不定义该函数。该声明是为派生类而保留的位置。
一个抽象类不能有实例对象,即不能由该类抽象来制造一个对象。
纯虚函数是在基类中为子类保留的一个位置,以便子类用自己的实在函数定义来重载之。如果在基类中没有保留位置,则就没有重载。
纯虚函数是一个没有定义函数语句的基类虚函数,纯虚函数的值是0.派生类必须为每一个基类纯虚函数提供一个相应的函数定义。
2.派生类可以继承基类的所有公有和保护的数据成员和成员函数。
保护的访问权限对于派生类来说是公有的,而对于其它的对象来说是私有的。即使是派生类也不能访问基类的私有的数据成员和成员函数。
在派生类中允许重载基类的成员函数。如果基类中的函数是虚函数,当使用指针或引用访问对象时,将基于实际运行时指针所指向的对象类型来调用派生类的函数。
3.笔试,面试中常考的C++虚拟继承的知识点
第一种情况: 第二种情况: 第三种情况 第四种情况:
class a class a class a class a
{ { { {
virtual void func(); virtual void func(); virtual void func(); virtual void func();
}; }; char x; char x;
class b:public virtual a class b :public a }; };
{ { class b:public virtual a class b:public a
virtual void foo(); virtual void foo(); { {
}; }; virtual void foo(); virtual void foo();
}; };
如果对这四种情况分别求sizeof(a), sizeof(b)。结果是什么样的呢?下面是输出结果:(在vc6.0中运行)
第一种:4,12
第二种:4,4
第三种:8,16
第四种:8,8
可参考:http://blog.csdn.net/wangqiulin123456/article/details/8059536
想想这是为什么呢?
因为每个存在虚函数的类都要有一个4字节的指针指向自己的虚函数表,所以每种情况的类a所占的字节数应该是没有什么问题
的,那么类b的字节数怎么算呢?看“第一种”和“第三种”情况采用的是虚继承,那么这时候就要有这样的一个指针vptr_b_a,这个指针叫虚类指针,也
是四个字节;还要包括类a的字节数,所以类b的字节数就求出来了。而“第二种”和“第四种”情况则不包括vptr_b_a这个指针,这回应该木有问题了
吧。
class a
{
virtual void func();
}; class b:public a
{
void foo();
};
此时:sizeof(a) = 4 , sizeof(b) = 4
class a
{
void func();
}; class b:public a
{
virtual void foo();
};
此时:sizeof(a) = 1 , sizeof(b) = 4
class a
{
void func();
}; class b:public a
{
void foo();
};
此时:sizeof(a) = 1 , sizeof(b) = 1
如下例:
class A
{
};
class A2
{
};
class B : public A
{
};
class C : public virtual B
{
};
class D : public A , public A2
{
};
以上答案分别是1 , 1 , 4 , 1. 这说明:空类所占空间为1,单一继承的空类空间也为1,多重继承的空类空间还是1.但是虚继承涉及到虚表(虚指针),所以sizeof(C)的大小为4
4.多继承的构造顺序
构造对象的规则需要扩展以控制多重继承。构造函数按下列顺序被调用:
- 任何虚拟基类的构造函数按照它们被继承的顺序构造;
- 任何非虚拟基类的构造函数按照它们被继承的顺序构造;
- 任何成员对象的构造函数按照它们声明的顺序调用;
- 类自己的构造函数。
5.C++子类继承父类后子类的大小
#include <iostream>
using namespace std;
class A
{
private:
int a;
}; class B:public A
{
private:
int b;
}; int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
return ;
}
刚开始我一想子类继承父类不会继承父类的私有变量,如此我认为结果为4,4(错误)。而事实上结果是4,8。也就是说子类把父类的私有变量也继承下来了,但是却无法访问,对于我这种菜鸟来说一下子没法转个弯来,后来看看资料焕然大悟,子类虽然无法直接访问父类的私有变量,但是子类继承的父类的函数却可以访问,不然的话如果只继承函数而不继承变量,哪么父类的函数岂不成了无米之炊了。所以必须把父类的所有变量都继承下来,这样既能保护父类的变量也能使用父类的函数。
6.继承的访问控制
继承分为公共继承、保护继承和私有继承。
在公共继承的类中,基类的每个成员在子类中保持同样的访问方式。即在基类中为public的成员,子类中可以访问,并据为public的;基类中为protected的成员,子类中也可访问之,并据为protected的;基类中为private的成员,在子类中不能访问之,这就像在应用程序中不能访问类中似有成员一样。
访问控制权限:
- 私有继承时,基类中不管是公有的,还是保护的或者为私有的,一律在子类中变成私有成员。
- 保护继承时,基类中公共和保护的成员在子类中变成保护的,而基类中私有的成员在子类中变成私有的。
- 公共继承时,基类中为公共、保护和私有的成员在子类中仍保持为公共、保护和私有的。
如果不标明继承为公共还是保护或者私有,则默认的继承是私有的。
在继承关系中,基类的private成员不但对应用程序隐藏,甚至对派生类也隐藏。而基类的保护成员则只对应用程序隐藏,而对派生类则毫不隐瞒。
一个私有的或保护的派生类不是子类,因为非公共的派生类不能做基类能做的所有的事。
保护继承与私有继承类似,继承之后的类相对于基类来说是独立的;保护继承的类对象,在公开场合同样不能使用基类的成员。
派生类的构造函数必须激活所有基类的构造函数,并把相应的参数传递给它们。
也可参看:http://www.cnblogs.com/heyonggang/archive/2013/04/17/3026107.html
7.虚函数
C++虚函数用于实现动态绑定,或者说多态,默认的类方法是非虚函数,需要动态绑定的类方法,必需显式声明函数 virtual。
virtual函数必需在子类中再次声明,明确告诉子类有这个方法,否则编译时报错,getRange方法未声明的错误。
#include <iostream>
using namespace std;
class Range {
public:
int width;
int height;
virtual float getRange(); Range(int w, int h):width(w), height(h){};
Range(){};
}; float Range::getRange() {
return width * height;
} class Square:public Range {
public:
virtual float getRange();
Square(){};
Square(int w, int h):Range(w, h){};
};
float Square::getRange() {
return width * width * ;
} class Circle:public Range {
public:
virtual float getRange();
Circle(){};
Circle(int w, int h):Range(w, h){};
};
float Circle::getRange() {
return 3.14 * width * width / ;
}
int main(int argc, char* args[]) {
Square s1(, );
Circle c1(, );
Range *r1 = &s1;
cout << r1->getRange() << endl;
Range *r2 = &c1;
cout << r2->getRange() << endl;
return ;
}
输出结果为:
18
6.28
Square 和 Circle 都由一个 Range 指针指向,当调用 getRange方法,动态找到相应 Square 和 Circle 实例的getRange方法进行调用。
纯虚函数
C++的纯虚函数用于表示一个类不能被创建实例, 必需是子类覆盖该方法的定义后,方可新建类实例,格式是在虚函数后面添加 = 0。
假如上例中的Range只是一个初步表示区域的一个类,那么它的getRange()方法需要由子类实现才有效,表示为:
virtual float getRange() = ;
此时不能再创建Range rt()实例,将会报错:
cannot declare variable ‘rt’ to be of abstract type ‘Range’
range2.cpp:3:13: note: because the following virtual functions are pure within ‘Range’:
但我们仍然可以新建Range的指针,指向Circle或者是Square
一个有意思的问题:为什么析构函数要设置成虚函数
Range *r1 = new Circle(3, 4);
如果析构函数不是虚函数,则r1在释放内存时,则调用提Range的析构函数。
结果并不是想要的结果,我们想要的结果是调到Circle对象的析构函数。
如果析构函数是虚函数,有多态的支持,r1调用Circle对象的析构函数,Circle对象的析构函数默认调用父类Range的析构函数,保证Circle和Range对象的内容都得到清除。
C++重要知识点小结---2的更多相关文章
- C++重要知识点小结---3
C++重要知识点小结---1:http://www.cnblogs.com/heyonggang/p/3246631.html C++重要知识点小结---2:http://www.cnblogs.co ...
- React及Nextjs相关知识点小结
React及Nextjs知识点小结 函数式组件和类组件区别是什么 1.函数式组件是用于创建无状态的组件,组件不会被实例化,无法访问this中的对象,无法访问生命周期方法,是无副作用的,相比于类组件函数 ...
- 【SpringBoot MQ 系列】RabbitMq 核心知识点小结
[MQ 系列]RabbitMq 核心知识点小结 以下内容,部分取材于官方教程,部分来源网络博主的分享,如有兴趣了解更多详细的知识点,可以在本文最后的文章列表中获取原地址 RabbitMQ 是一个基于 ...
- SpringBoot 系列教程之事务隔离级别知识点小结
SpringBoot 系列教程之事务隔离级别知识点小结 上一篇博文介绍了声明式事务@Transactional的简单使用姿势,最文章的最后给出了这个注解的多个属性,本文将着重放在事务隔离级别的知识点上 ...
- disruptor笔记之四:事件消费知识点小结
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- promise知识点小结
断断续续学习es6也有一段时间了,趁着开学空闲对知识点做一些小结. 为什么使用promise 谈到Promise,我们知道,这是社区较理想的异步编程解决方案.想要掌握promise,我们首先要知道其提 ...
- shell知识点小结
目录 引言 shell中的数组 数组的定义 数组的使用 实际的例子 shell中大小的比较 shell中的括号 shell中函数的定义 杂项知识点 字符串转数组 常用判断标志 linux后台运行相关 ...
- Vuejs技术栈知识点小结
前言 上家公司的项目主要是使用jQuery和Angular1,然后自己学了React,没想到来到这家公司突然开始做vue,不过vue还是挺容易上手的.下面是vue技术栈的一些总结,都是来自官网,主要是 ...
- Java 基础知识点小结
小知识点 所有的程序,都要定义在类里面: 异常 定义方法时,使用 throws 可以用来捕获方法体内没有捕获的异常,然后以 SomeException 抛出异常 java是解释型语言.java虚拟机能 ...
随机推荐
- TForm的显示过程
新建一个空窗体项目,然后运行,此时首先运行: procedure TApplication.Run; begin FRunning := True; try AddExitProc(DoneAppli ...
- idea自动生成serialVersionUID
Setting->Plugins 找到一个叫 GenerateSerialVersionUID 的插件 下载安装好,alt+insert就可以看到 默认情况下Intellij IDEA是关闭了 ...
- chrome开发配置(一)安装配置工具
1.下载depot_tools,解压到本地,然后将解压后的depot_tools根目录添加到path环境变量: depot_tools下载地址 2.cmd 运行gclient,git比较大,有100M ...
- Data Flow ->> Import Column & Export Column
这两个transformation的作用是把DT_TEXT, DT_NTEXT, DT_IMAGE类型的数据在文件系统和数据库间导出或者导入.比如把某个数据库表的image类型的字段导出到文件系统成为 ...
- 乙醇脱氢酶力场文件的处理(含ZN,NAD,乙醇)
很多蛋白质在行驶生物催化反应(如ATP水解,氨基酸的乙酰化,CoA的去乙酰化,甲基化等等)都需要金属离子(Mg,Zn,Ca等等)的参与,换句话说,金属离子对蛋白功能是必须的.模拟金属酶体系,现在也是分 ...
- slot signal机制
有一个比较 经典的实现:http://sigslot.sourceforge.net/很精简的 signal slot的实现,跨平台.webrtc项目在用,我在自己项目里也用了.这个源码有2000多行 ...
- 《Linux内核设计与实现》读书笔记 - 目录 (完结)【转】
转自:http://www.cnblogs.com/wang_yb/p/3514730.html 读完这本书回过头才发现, 第一篇笔记居然是 2012年8月发的, 将近一年半的时间才看完这本书(汗!! ...
- Pascal's Triangle(帕斯卡三角)
Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Retur ...
- 从零开始学数据分析,什么程度可以找到工作?( 内附20G、5000分钟数据分析工具教程大合集 )
从零开始学数据分析,什么程度可以找到工作?( 内附20G.5000分钟数据分析工具教程大合集 ) 我现在在Coursera上面学data science 中的R programming,过去很少接 ...
- find-all-anagrams-in-a-string
https://leetcode.com/problems/find-all-anagrams-in-a-string/ package com.company; import java.util.A ...