【C++】C++ 知识点100题

1 多态的实现

存在虚函数的类至少有一个(多继承会有多个)一维的虚函数表叫做虚表(virtual table),属于成员,虚表的元素值是虚函数的入口地址,在编译时就已经为其在数据端分配了空间。编译器另外还为每个类的对象提供一个 虚表指针(vptr),指向虚表入口地址,属于对象成员。在实例化派生类对象时,先实例化基类,将基类的虚表入口地址赋值给基类的虚表指针,当基类构造函数执行完时,再将派生类的 虚表入口地址 赋值给 基类虚表指针(派生类和基类此时共享一个虚表指针,并没有各自都生成一个),在执行父类的构造函数。
以上是C++多态的实现过程,可以得出结论:

  • 1 有虚函数的类必存在一个虚表。
  • 2 虚表的构建:
  • 基类的虚表构建,先填上虚析构函数的入口地址,之后所有虚函数的入口地址按在类中声明顺序填入虚表;
  • 派生类的虚表构建,先将基类的虚表内容复制到派生类虚表中,如果派生类覆盖了基类的虚函数,则虚表中对应的虚函数入口地址也会被覆盖,为了后面寻址的一致性。
class Person{ 
     . . . 
 public : 
    Person (){} 
    virtual ~Person (){}; 
    virtual void speak (){}; 
    virtual void eat (){}; 
 }; 
 
class Girl : public Person{ 
     . . . 
   public : 
   Girl(){} 
   virtual ~Girl(){}; 
   virtual void speak(){}; 
   virtual void sing(){};

虚表构建图

虚函数表中有序放置了父类和子类中的所有虚函数,并且相同虚函数在类继承链中的每一个虚函数表中的偏移量都是一致的。所以确定的虚函数对应virtual table中一个固定位置n,n是一个在编译时期就确定的常量,所以,使用vptr加上对应的n,就可以得到对应的函数入口地址。C++采用的这种绝对地址+偏移量的方法调用虚函数,查找速度快执行效率高,时间复杂度为O(1)
这里概括一下虚函数的寻址过程:

1、获取类型名和函数名

2、从符号表中获得当前虚函数的偏移量

3、利用偏移量得到虚函数的访问地址,并调用虚函数。vptrn

2  C/C++的区别

C面向过程,C++面向对象。C++几乎是C的一个超集,几乎包含了C。

3 const 关键字

常变量: const 类型说明符 变量名

常引用: const 类型说明符 &引用名

常对象: 类名 const 对象名

常成员函数: 类名::fun(形参) const

常数组: 类型说明符 const 数组名[大小]

常指针: const 类型说明符* 指针名 ,类型说明符* const 指针名

用法1:常量
取代了C中的宏定义,声明时必须进行初始化(!c++类中则不然)。const限制了常量的使用方式,并没有描述常量应该如何分配。如果编译器知道了某const的所有使用,它甚至可以不为该const分配空间。最简单的常见情况就是常量的值在编译时已知,而且不需要分配存储。―《C++ Program Language》
 用const声明的变量虽然增加了分配空间,但是可以保证类型安全用法2:指针和常量
使用指针时涉及到两个对象:该指针本身和被它所指的对象。将一个指针的声明用const“预先固定”将使那个对象而不是使这个指针成为常量。要将指针本身而不是被指对象声明为常量,必须使用声明运算符*const。
所以出现在 * 之前的const是作为基础类型的一部分:
char *const cp; //到char的const指针
char const *pc1; //到const char的指针
const char pc2; //到const char的指针(后两个声明是等同的)
从右向左读的记忆方式:
cp is a const pointer to char. 故pc不能指向别的字符串,但可以修改其指向的字符串的内容
pc2 is a pointer to const char. 故
pc2的内容不可以改变,但pc2可以指向别的字符串
且注意:允许把非 const 对象的地址赋给指向 const 对象的指针,不允许把一个 const 对象的地址赋给一个普通的、非 const 对象的指针。用法3:const修饰函数传入参数
将函数传入参数声明为const,以指明使用这种参数仅仅是为了效率的原因,而不是想让调用函数能够修改对象的值。同理,将指针参数声明为const,函数将不修改由这个参数所指的对象。
通常修饰指针参数和引用参数:
void Fun( const A *in); //修饰指针型传入参数
void Fun(const A &in); //修饰引用型传入参数用法4:修饰函数返回值
可以阻止用户修改返回值。返回值也要相应的付给一个常量或常指针。用法5:const修饰成员函数(c++特性)
const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数;
const对象的成员是不能修改的,而通过指针维护的对象确实可以修改的;
const成员函数不可以修改对象的数据,不管对象是否具有const性质。编译时以是否修改成员数据为依据进行检查。

const 和 宏的区别

【参考答案】

(1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。

  而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应) 。

(2)有些集成化的调试工具可以对 const 常量进行调试,但是不能对宏常量进行调试。

4 malloc/free 和new/delete 区别

相同点:都可用于申请动态内存和释放内存
不同点:
简单点说,malloc只分配指定大小的堆内存空间,而new可以根据对象类型分配合适的堆内存空间,当然还可以通过重载operator new 自定义内存分配策略,其次还能够构造对象,free释放对应的堆内存空间,delete,先执行对象的析构函数,在释放对象所占空间。
malloc与free是C++/C 语言的标准库函数,new/delete 是C++的运算符。malloc分配时的大小是人为计算的,返回类型是void*,使用时需要类型转换,而new在分配时,编译器能够根据对象类型自动计算出大小,返回类型是指向对象类型的指针,其封装了sizeof和类型转换功能,实际上new分为两步,第一步是通过调用operator new函数分配一块合适,原始的,未命名的内存空间,返回类型也是void *,而且operator new可以重载,可以自定义内存分配策略,甚至不做内存分配,甚至分配到非内存设备上,而malloc无能为力,第二步,调用构造函数构造对象,new将调用constructor,而malloc不能;delete将调用destructor,而free不能

5 指针和引用的区别

1、引用在创建时必须初始化,引用到一个有效对象,不是对象,不占用内存空间;而指针在定义时不必初始化,可以在定义后的任何地方重新赋值,是对象,占用内存空间。
2、指针可以是NULL,引用不行
3、引用貌似一个对象的小名,一旦初始化指向一个对象,就不能将其他对象重新赋值给该引用,这样引用和原对象的值都会被更改。

6 C++中堆和栈的区别

一、预备知识—程序的内存分配
一个由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的 全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另 一块区域。 - 程序结束后由系统释放。
4、文字常量区 —常量字符串就是放在这里的。程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

二、例子程序
这是一个前辈写的,非常详细
//main.cp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值