对C++基础知识的总结(主要针对面试)

SeanyBrake 2016-03-19 06:49:46
C++的魅力在于其丰富多彩的性格特征:其行为方式既可以像C一样面向过程也可以面向对象(专注Class 很多年)、封装性(城府很深)、继承性(富二代)、多态性(多重人格/精神分裂/变态),谜一样的男神,常年霸占编程语言“琅琊榜”前三甲(今年排行第一的高富帅是Java)。本篇将根据以下C++男神养成的大致攻略图所对应的性格特征进行简要的分析。
1.面向对象
面向对象的三大特性:封装、继承、多态。
类和对象:类由数据成员和成员函数构成,代表抽象派,玩的就是概念,某种意义上来说是一种行为艺术;而对象是具体的,比如说过年回家和老爹下中国象棋,发现棋盘上少了一对‘象’,那是你爸在告诉你该找“对象”了(单身狗表示选择Go Die)。
  封装:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的类进行信息隐藏。(C++最大的优点:可以隐藏代码的实现细节,使得代码更模块化)
  继承:可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展,但是基类的构造函数、复制构造函数、析构函数、赋值运算符不能被派生类继承。(优点是实可以扩展已存在的代码模块类)
多态:一个类实例的相同方法在不同情形有不同表现形式。多态实现的两种方式:将子类对象的指针赋给父类类型的指针或将一个基类的引用指向它的派生类实例。(其中比较重要的是虚函数的使用以及指针或引用)
this指针:一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。this作用域是在类的内部,当在类的非静态(前面没加Static)成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,各成员的访问均通过this指针进行。(静态成员是没有this指针的)

2.封装性
(1)拷贝函数
浅拷贝:所谓浅拷贝,指的是在对象复制时,只是对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。
深拷贝:在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间。
(2)构造与析构函数
构造函数:主要用来初始化数据。
析构函数:主要用来释放堆区申请的内存空间。
(3)指针与引用
相同点:
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
不同点:
指针是一个实体,而引用仅是个别名;
引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
引用没有const,指针有const,const的指针不可变;
引用不能为空,指针可以为空;
sizeof(引用)得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
指针和引用的自增(++)运算意义不一样;
引用是类型安全的,而指针不是 (引用比指针多了类型检查)。
举个栗子: void fun (int *a,int *b) voidfun (int &a,int &b)
{ {
int c = 0; intc = 0;
c = *a; c = a;
*a = *b; a = b;
*b = c; b = c;
} }
fun(&a,&b); fun(a, b);
const int x=3; int *y= &x; (错误)
int x=3; const int *y=&x; (可行)

3.继承性
派生类继承方式:
a.公有继承(public):基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的。
b.保护继承(protected):基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。
c.私有继承(privatem默认):基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
友元函数:
概念:友元函数是一种定义在类外部的普通函数,但它需要在类体内进行说明
friend 类型友元函数名(参数表);
特点:
友元函数可以访问类中的所有成员,一般函数只能访问类中的公有成员。
某类的友元函数的作用域并非该类作用域。
友元函数破坏了面向对象程序设计类的封装性,所以友元函数如不是必须使用,尽量少用。

4.多态性

1 多态性:

(1)多态
相同对象收到不同消息或不同的对象接收相同的命令而做出的不同反应叫做多态。
举个栗子:在我们玩拳皇游戏,按下的不同按键,不同人物所作出的不同动作招式。
多态分为:静态绑定(早绑定)和动态绑定(晚绑定)两种。
a. 静态绑定:函数重载;
b. 动态绑定:虚函数;
(2)函数
有默认参数值的函数参数,必须在参数表的最右端(靠右原则)。
无实参时使用函数默认值,有实参时覆盖默认值。
a. 函数重载:
b. 运算符重载:
c. 内联函数Inline:编译时将函数体代码和实参代替函数调用语句(在函数声明前加个Inline)。
l 优点:使用内联函数,效率高,运行快。
l 使用条件:
内联编译的建议性由编译器决定。
逻辑简单调用频繁的函数,建议使用内联函数。
递归函数无法使用内联函数。
d. 虚函数:(普通虚函数、虚析构函数、纯虚函数{抽象类/接口类}、虚函数表)
(3)重写与重载:(企业面试题)

方法的重写Overriding和重载Overloading是多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了,而且如果子类的方法名和参数类型和个数都和父类相同,那么子类的返回值类型必须和父类的相同;如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloading的方法是可以改变返回值的类型。也就是说,重载的返回值类型可以相同也可以不同。
(4)const和#define:
• define宏定义不会做类型检查(容易出错),const拥有类型,会执行相应的类型检查
  • define仅仅是宏替换,不占用内存,而const会占用内存
• const内存执行效率更高,编译器可能将const变量保存在符号表中,而不会分配存储空间,这使得它成为一个编译期间的常量,没有存储和读取的操作,而使用#define定义的是一个简单的函数时,大都使用内联函数替换。
Black宇笔记:定义:define不会做类型检查,const会做类型检查
内存:define不占用内存,而const占用内存
作用:define简单的宏替换,const防止内存被篡改
(5)static静态:
在C语言中,关键字static有三个明显的作用:
1)在函数体内,一个被声明为静态的变量在这一函数被调用过程中维持上一次的值不变,即只初始化一次(该变量存放在静态变量区,而不是栈区)。
2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外访问。
3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
4)在类中的static成员变量意味着它为该类的所有实例所共享,也就是说当某个类的实例修改了该静态成员变量,其修改值为该类的其它所有实例所见;
5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量(当然,可以通过传递一个对象来访问其成员)。
5.内存管理

申请或者归还内存资源就叫做内存管理。
1)堆区和栈区:

  从内存角度来说:栈区(stack)由编译器自动分配释放,存放函数的参数值,局部变变量的值等,其操作方式类似于数据结构中的栈,可静态亦可动态分配。堆区(heap)一般由程序员分配释放,若程序员不释放,可能造成内存泄漏,程序结束时可能由OS回收。只可动态分配,分配方式类似于链表。
从数据结构角度来说:堆可以被看成是一棵树,如:堆排序。而栈是一种先进后出的数据结构。
2)malloc VS new

1.malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。但它们都可用于申请动态内存和释放内存。
2.对于非内部数据类型的对象而言,用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free,因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,和一个能完成清理与释放内存工作的运算符delete。
3.new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void*指针。new delete在实现上其实调用了malloc,free函数。
4.new 建立的是一个对象;malloc分配的是一块内存。
Black宇笔记:本质:malloc 和free是函数,而new和delete是运算符
定义:malloc 和free是分配和释放一块内存,构建对象时不会自动调用构造和析构函数,而new和delete是建立和释放一个对象,构建对象时会自动调用构造和析构函数。
...全文
4183 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
hongss 2016-03-22
  • 打赏
  • 举报
回复
这个好
SeanyBrake 2016-03-22
  • 打赏
  • 举报
回复
引用 4 楼 PPower的回复:
new delete在实现上其实调用了malloc,free函数。 //这个有问题。。。。new delete在实现上并非调用了malloc,free 应该认为,new delete 与 malloc,free 在不同的编译器中,可能使用不同的内存管理器,他们是互不兼容的, malloc,free使用于C的内存管理器中,new delete 使用于C++的内存管理器中,这两个管理器在一些版本中是一样的,但很多情况下并不一样。这是内存调度优化算法不一致产生的问题,只能说:混用是不规范的,但不一定出错,看你运气了。我们希望代码是强壮的,不是看运气。 即不要写出类似这样的代码: int *a = malloc(1000); delete a ; 或者 int *a = new[1000]; free( a ); 对一些编译器而言,这样混合使用,可能会造成其内置的内存管理器失效或崩溃,产生不可预测的错误。 这是不能混用的,在BCB的很多版本中就是如此。
好的,谢谢提出,这个确实写错了,这也是笔试面试常见题型啊
SeanyBrake 2016-03-22
  • 打赏
  • 举报
回复
引用 1 楼 我不懂电脑的回复:
说得很好,总结得很好。
谢谢!!!以后会多分享一些自己的学习,工作后会分享一些工作的经验
勉励前行 2016-03-22
  • 打赏
  • 举报
回复
new delete在实现上其实调用了malloc,free函数。 //这个有问题。。。。new delete在实现上并非调用了malloc,free 应该认为,new delete 与 malloc,free 在不同的编译器中,可能使用不同的内存管理器,他们是互不兼容的, malloc,free使用于C的内存管理器中,new delete 使用于C++的内存管理器中,这两个管理器在一些版本中是一样的,但很多情况下并不一样。这是内存调度优化算法不一致产生的问题,只能说:混用是不规范的,但不一定出错,看你运气了。我们希望代码是强壮的,不是看运气。 即不要写出类似这样的代码: int *a = malloc(1000); delete a ; 或者 int *a = new[1000]; free( a ); 对一些编译器而言,这样混合使用,可能会造成其内置的内存管理器失效或崩溃,产生不可预测的错误。 这是不能混用的,在BCB的很多版本中就是如此。
我不懂电脑 2016-03-21
  • 打赏
  • 举报
回复
说得很好,总结得很好。

13,826

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧