C++知识点总结(四)——面向对象的编程细节总结
1.空类的默认函数
一般情况下,对于任意一个类A,如果程序员不显示的声明和定义上述函数,C++编译器将会自动的为A产生4个public inline(公有、内联)的默认函数,这4个函数最常见的形式为:
(1)默认构造函数 A() {}
(2)默认拷贝构造函数 A(const A&){}
(3)默认析构函数 ~A() {}
(4)默认赋值函数 A& operator = (const A &) {}
2.静态成员
在C++中,类的静态成员(static member)必须在类内声明,在类外初始化(否则意味着全员所有)。如下:
class A
{
private:
static int count ; // 类内声明
}; int A::count = 0 ; // 类外初始化,不必再加static关键字
如果限制对静态成员的访问,可以定义公有静态成员去访问。同样常量成员也不能在类中初始化。类中初始化的成员只有一种,那就是静态常量成员。静态成员可以使用“.”和“::”访问。注意:
(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。
(2) 不能将静态成员函数定义为虚函数。
(3) 由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊,变量地址是指向其数据类型的指针,函数地址类型是一个“nonmember 函数指针”。
(4) static 并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问时间,节省了子类的内存空间。静态数据成员是静态存储的,所以必须对它进行初始化。初始化时不加该成员的访问权限控制符 private、public;
(5)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。初始化以及使用时,使用作用域运算符来标明它所属类;
3.析构函数与构造函数
析构函数
基类的析构函数为什么设置为虚函数:当基类指针指向派生类对象时,不会出现派生类的析构函数未被调用,从而导致内存泄露,因为由于静态联编,此时只会调用基类的对应析构函数。注意,一旦某个类的析构函数设置为虚,则其所有派生类的析构函数都是虚函数。
构造函数
(1)构造函数不能为虚函数。因为创建函数时,必须知道准确类型。
(2)倘若派生类构造函数没有显式调用基类的构造函数,则调用默认构造函数。
(3)一旦定义其它构造函数还需要默认构造函数的,需要自己定义
(4)最好提供显式默认构造函数,使得数据成员初始化为合理的值(特别是包括指针成员时)
(5)构造函数在完成其工作前,对象并不存在
(6)构造函数声明为private能阻止编译器生成拷贝构造函数。
4.静态局部变量
(1) 静态局部变量在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,存储在动态存储区空间(而不是静态存储区空间),函数调用结束后即释放。
(2) 为静态局部变量赋初值是在编译时进行值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的 值。而为自动变量赋初值,不是在编译时进行的,而是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
(3) 如果在定义局部变量时不赋初值的话,对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符型变量)。而对自动变量来说,如果不赋初 值,则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是不确定的。
(4) 虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的,也就是说,在其他函数中它是“不可见”的。
5.虚函数
(1)虚函数要求同名同参,但是可以不同的返回类型。一旦派生类的对应同名虚函数有不同参数,则基类虚函数将被隐藏。
(2)一旦基类函数声明为虚函数,则派生类同名同参的函数不用显式说明为虚函数。同样,在类外定义时,也不需要关键字声明。
(3)若基类中,虚函数本身被重载多次。则在派生类中,必须对所有的重载版本进行重定义,否则未重定义的版本将会被隐藏。新定义可以直接调用基类版本从而满足某些重载版本定义不需要修改的情况(使用作用域符::)。
(4)友元函数非类成员,故不能声明为虚。但可以通过让友元函数调用虚成员函数来解决友元的虚拟问题。
(5)派生类将始终使用最新的虚函数版本(从派生链向下索引)。
(6)虚函数不能滥用。存在虚表——系统开销,不想派生的类没必要使用虚构成员函数。
6.纯虚函数和抽象类
抽象类不能生成对象,只能作为基类。但是基类中的纯虚函数可以有定义。当函数没有实现方法或者需要子类来定义实现方法的时候,可以在父类中定义纯虚函数。如代码:
class test{
public:
virtual void print();
virtual void order()=0;
int array[20];
};
void test::print(){
order();
printf("打印结果: ");
for(int i=0; i<20; i++)
printf("%d ", array[i]);
}
打印函数中,调用了order函数对array进行了排序,然后输出结果。问题是不知道order函数是什么算法,或者说order函数因人而异,所以无法确定!于是当不同的子类继承这个父类的时候,定义不同的实现方法,那么实例化这个子类的时候,这个纯虚函数就有了不同的方法。这也解释了为什么包含纯虚函数的抽象类为什么不能实例化,因为它中间有函数根本不知道是怎么实现!当然我们可以用其他方法避免使用纯虚函数,比方说在子类中重写print方法,但是这样一来等于除了order函数代码以外所有的代码都要重新复制一遍,当继承类越来越多的时候,要修改print等于这一堆继承类都要修改。简化了编程使得面向对象的方法更加灵活。
7.引用类型形参和返回值
(1)在编写使用对象为形参的函数时,应使用引用来传递对象。能够节约生成和析构临时对象的时间继而提高效率,对于不修改参数的函数,还应声明为const类型。另外基类已用也接受派生类对象。
(2)返回为引用同样也相同的节约时间提高效率。但是应避免返回对临时对象的引用。另外倘若形参为引用,注意要返回形参时,也应该返回引用。
(3)基类指针和基类引用都可以(隐式,即不经过转换)地指向派生类对象,反过来则不可以(除非显式的转换,但是可能没意义)。当然,派生类对象也可以作为实参赋给以基类指针和基类引用为形参的函数。
(4)当把基类对象赋值给派生类对象时。当且仅当派生类存在接受基类对象和其它参数的转换构造函数或者有重载了的接受基类对象的对应的赋值运算符函数。才能隐式地将基类对象赋值给派生类对象、引用、指针.
8.const关键字
(1)const形参保证不修改实参值。对于const指针和引用表征不会修改指针指向和引用对象
(2)const类型函数,表征函数不修改调用他的对象的值
(3)返回const类型,表示返回不能修改值的变量。
9.基类函数和其继承特性
(1)构造函数,析构函数,赋值运算符都不能继承。析构函数先调用派生类的析构函数再调用基类的析构函数,与构造的顺序相反。友元函数也不能继承,因为其非成员函数。
(2)派生类的构造函数自动调用基类的默认构造函数,如果成员初始化列表中没显式指定其他构造函数(一旦指定其他的,也应该提供默认构造函数)
(3)派生类可以使用通过作用域解析运算符显式地调用公有和保护的基类方法。
(4)派生类的友元函数可以通过强制类型转换,使用转换后的指针或者引用调用基类的友元函数。
(5)虚基类(ABC)包含至少一个纯虚函数,且不一定(也可以定义)需要定义虚的方法。
10.其它
(1)对于外部世界来说,protected和private相似。对于派生类来说,protected和public相似。但是慎用protected,因为在派生类中也可以修改基类成员变量,破坏了类的封装性。
(2)宏、内联函数、模板都在编译时解析,虚函数在运行时确定。
(3)对于含单参构造函数的某个类A,A a=5 合法。此时隐含类型转换,可以使用explicit关键字声明消除这种隐含转换。
(4)初始化列表(A:b(i),c(j){})的初始化顺序依据成员变量声明的顺序执行,因此赋值的时候要分先后,避免随机值出现(例如c可能使用c(b+i)初始化,而b因为定义的顺序在c之后而在c之后初始化,此时c产生随机值)。
(5)强制转换类型重载定义。operator char*()。char*是目标类型。
(6)虚函数机制,破环类的封装。假设基类为public,派生类为private的虚函数多态。通过虚表,使用基类指针仍然能够访问派生的对应重载虚函数,尽管其为private。
虚函数必须同名同参同返回(注意函数重载可以不同返回)
(7)若当前类含有对象时,则构造顺序:基类>本层对象>本层构造函数
C++知识点总结(四)——面向对象的编程细节总结的更多相关文章
- C++面向对象高级编程(四)基础篇
技术在于交流.沟通,转载请注明出处并保持作品的完整性. 一.Static 二.模板类和模板函数 三.namespace 一.Static 静态成员是“类级别”的,也就是它和类的地位等同,而普通成员是“ ...
- 长文梳理muduo网络库核心代码、剖析优秀编程细节
前言 muduo库是陈硕个人开发的tcp网络编程库,支持Reactor模型,推荐大家阅读陈硕写的<Linux多线程服务端编程:使用muduo C++网络库>.本人前段时间出于个人学习.找工 ...
- 谈面向对象的编程(Python)
(注:本文部分内容摘自互联网,由于作者水平有限,不足之处,还望留言指正.) 今天中秋节,也没什么特别的,寻常日子依旧. 谈谈面向对象吧,什么叫面向对象? 那么问题来了,你有对象吗? 嗯,,,那我可 ...
- C++面向对象高级编程(一)基础篇
技术在于交流.沟通,转载请注明出处并保持作品的完整性. 概要: 知识点1 构造函数与析构函数 知识点2 参数与返回值 知识点3 const 知识点4 函数重载(要与重写区分开) 知识点5 友元 先以C ...
- PHP面向对象(OOP)编程入门教程
面向对象编程(OOP)是我们编程的一项基本技能,PHP5对OOP提供了良好的支持.如何使用OOP的思想来进行PHP的高级编程,对于提高 PHP编程能力和规划好Web开发构架都是非常有意义的.下面我们就 ...
- php面向对象(OOP)编程完全教程
摘自:http://www.php-note.com/article/detail/41 面向对象编程(OOP)是我们编程的一项基本技能,PHP5对OOP提供了良好的支持.如何使用OOP的思想来进行P ...
- Java最重要的21个技术点和知识点之JAVA面向对象
(二)Java最重要的21个技术点和知识点之JAVA面向对象 写这篇文章的目的是想总结一下自己这么多年JAVA培训的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能分享给刚刚入门的J ...
- Java 面试知识点解析(四)——版本特性篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- C++面向对象高级编程(九)Reference与重载operator new和operator delete
摘要: 技术在于交流.沟通,转载请注明出处并保持作品的完整性. 一 Reference 引用:之前提及过,他的主要作用就是取别名,与指针很相似,实现也是基于指针. 1.引用必须有初值,且不能引用nul ...
随机推荐
- 使用BeanUtils方法拷贝不上问题
最近在项目中,发现BeanUtils.copyProperties方法拷贝bean属性时候,有的时候会失效.最后发现是由于项目中引用了spring和common两个包,都有BeanUtils方法,错误 ...
- spring boot: 线程池ThreadPoolTaskExecutor, 多线程
由于项目里需要用到线程池来提高处理速度,记录一下spring的taskExecutor执行器来实现线程池. ThreadPoolTaskExecutor的配置在网上找了很多解释没找到,看了下Threa ...
- The import javax.servlet.jsp.JspWriter cannot be resolved' error
Add servlet-api.jar and jsp-api.jar from Tomcat 6.0 library to ecipse project.
- 圆形ImageView(可设置边缘厚度和颜色)--第三方开源--CircleImageView
下载地址:https://github.com/hdodenhof/CircleImageView 使用的时候直接在xml中: <de.hdodenhof.circleimageview.Cir ...
- [软件工程基础]团队作业Week3
团队介绍 团队名:弗朗明哥舞步 团队角色 开发:杨艺媛,易子沐,赵晓宇,夏欣怡 测试:张华杰 PM:刘斯盾 刘斯盾 我是刘斯盾,喜欢编程,喜欢运动!很高兴和大家一起开发这个项目! 杨艺媛 我叫杨艺媛, ...
- 《ASP.NET夜话》 - 书摘精要
(P14) 如果客户端启用了Cookie,那么客户端与服务器之间通过Cookie来传递SessionID的值:如果客户端没有启用Cookie,就会通过URL来传递SessionID的值: (P15) ...
- hdu-2544-最短路(dijkstra算法模板)
题目链接 题意很清晰,入门级题目,适合各种模板,可用dijkstra, floyd, Bellman-ford, spfa Dijkstra链接 Floyd链接 Bellman-Ford链接 SPFA ...
- Codeforces Round #286 (Div. 2)B. Mr. Kitayuta's Colorful Graph(dfs,暴力)
数据规模小,所以就暴力枚举每一种颜色的边就行了. #include<iostream> #include<cstdio> #include<cstdlib> #in ...
- NOIP模拟题 斐波那契数列
题目大意 给定长度为$n$序列$A$,将它划分成尽可能少的若干部分,使得任意部分内两两之和均不为斐波那契数列中的某一项. 题解 不难发现$2\times 10^9$之内的斐波那契数不超过$50$个 先 ...
- UVA - 1610 Party Games (字符串比较)
给你n(n为偶数)个字符串,让你找出一个长度最短且字典序尽量小的字符串,使得一半的字符串小于等于该串,一半的字符串大于该串. 紫薯上说这道题有坑,但其实思路对了就没什么坑. 很明显,只要取夹在中间两个 ...