1. c++中类中非静态成员函数 默认访问的时候会有一个this指针指向它,而静态成员函数没有。this 指针的作用就是其实是改对象的一个地址,而静态成员函数因为在全局区域它不属于任何一个对象因此没有this 指针。
2. c++ 中类和结构体的区别,c++中类结构体的区别不像c#中,类是引用类型结构体是值类型.结构体不能继承。由于c++是从c演变而来因此c++中结构体是对c中结构体的保留。c++结构体基本上与类没有任何区别,除了默认结构体中成员是public而类是private,继承的时候c++默认继承后的成员访问权限private(虽然父类是public),而结构体继承后访问权限是public
3. 虚函数表
- 为什么会有虚函数?因为为了实现多态。
- 定义:虚函数表就是存储了类中虚函数的一张表,该表是一个一维数组,存储了每一个虚函数的地址。
- 虚函数表什么时候创建? 编译时期创建
- 使用虚函数的缺点
很容易理解 c++执行效率高的原因就是把很多事情在编译期间做好了,虚函数表的创建也不例外。在编译期间父类和子类都会创建一个虚函数表(NOTI:所以不管一个带有虚函数的类实例化了多少对象,该类的虚函数表都只有一个)。那么在执行的时候是什么知道执行父类的还是子类的虚函数呢?编译器是通过为每一个带有虚函数的对象创建自动创建一个虚函数指针
- 虚函数表什么时候初始化?在构造函数中进行虚表的创建的虚表指针的初始化
构造函数调用的顺序是先调用父类的构造函数,之后在完成子类的构造函数。它初始化虚表指针,将该虚表指针指向父类的虚表。当执行子类的构造函数时,虚表指针被重新赋值,指向自身的虚表。子类的对象构造完毕后,其内部的虚表指针也就被初始化为指向子类的虚表。举例子 :通过父类的指针base指向子类对象derive 时,调用base.虚函数Name,由于虚函数指针指向子类,所以会调用子类的虚函数。
子类的析构函数为什么定义为虚函数?如果析构函数不是虚函数,那么释放内存时候,编译器会使用静态联编,认为p就是一个基类指针,调用基类析构函数,这样子类对象的内存没有释放,造成内存泄漏。定义成虚函数以后,就会动态联编,先调用子类析构函数,再基类。(NOTI:我认为这是c++ 设计不好的地方)
Reference:
Typically, the compiler creates a separate virtual method table for each class. When an object is created, a pointer to this table, called the virtual table pointer, vpointer or VPTR, is added as a hidden member of this object. As such, the compiler must also generate "hidden" code in the constructors of each class to initialize a new object's virtual table pointer to the address of its class's virtual method table.
Many compilers place the virtual table pointer as the last member of the object; other compilers place it as the first; portable source code works either way.[2] For example, g++ previously placed the pointer at the end of the object。
https://blog.youkuaiyun.com/qq_34484472/article/details/78232465
使用虚函数缺点:事物都有两面性,使用虚函数的情况也不例外:使用虚函数的时候,因为需要额外的维护一张虚函数表,并且需要在运行的时候去查找对应的虚函数。所以有加大代码量和会导致运行变慢的特点。
4.当提示找不到连接符号的时候用#pragma comment(lib,"xxx.lib") xxx代表是找不到的库名.
5.用正则表达式搜索方法名比直接通过关键字搜索更精确, 比如需要搜索三个参数的方法:
functionName\((.*?),(.*?),(.*?)\) ,可以扩展成更多
6 静态链接库和动态链接库区别
This concept might be a little bit too broad to explain, but i will try to give you a basic idea from which you can study further.
Firstly, you need to know what a library is. Basically, a library is a collection of functions. You may have noticed that we are using functions which are not defined in our code, or in that particular file. To have access to them, we include a header file, that contains declarations of those functions. After compile, there is a process called linking, that links those function declarations with their definitions, which are in another file. The result of this is the actual executable file.
Now, the linking as I described it is a static linking. This means that every executable file contains in it every library (collection of functions) that it needs. This is a waste of space, as there are many programs that may need the same functions. In this case, in memory there would be more copies of the same function. Dynamic linking prevents this, by linking at the run-time, not at the compile time. This means that all the functions are in a special memory space and every program can access them, without having multiple copies of them. This reduces the amount of memory required.
As I mentioned at the beginning of my answer, this is a very simplified summary to give you a basic understanding. I strongly suggest you study more on this topic.
静态库 :函数与数据被编译为二进制文件(window 名字为lib,linux 平台为.a)在使用静态库的情况下, 在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件(.EXE文件)。当发布产品时,只需要发布这个可执行文件,并不需要发布被使用的静态库.
动态库: window 平台往往提供了两个文件 一个(仅仅显式加载才有).lib 一个 .dll。虽然引入lib ,但是这个lib 不同于静态库的lib ,它只是为导入的dll提供了一些信息,包含了dll 的函数和变量的符号名字,dll中才是包含了实际的函数和数据。 那么在编译的时候只需要链接 其中的lib文件,而dll 在实际运行的时候才去动态的加载,将dll映射到改进程的地址空间中。
另外: 动态库还分为显式加载和隐式加载。
7.指针指针存在引用计数,当出现两个智能指针循环引用的时候,就会出现内存泄漏问题,这个时候可以通过弱指针引用来完成 ,因为弱指针没有用引用计数来管理内存的释放,当它最后一个引用被消耗的时候 对象也就被释放了。参考https://blog.youkuaiyun.com/Xiejingfa/article/details/50772571
8.const 与 define 区别?
const定义变量有作用域和类型检查编译的时候会替换。 define 预处理的时候替换。
const对象只能调用const方法, 如果一个类有const修饰和没有const修饰的两个重载方法,该类对应的const对象调用默认的是const的方法,非const对象调用的非const方法。
9. 深拷贝和浅拷贝区别
在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的;但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象,所以,此时,必须采用深拷贝。
10 深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。简而言之,当数据成员中有指针时,必须要用深拷贝,对象需要初始化的时候,调用拷贝构造函数,对象直接赋值的时候,调用赋值拷贝构造函数,因为该对象已经完成了初始化所以赋值构造函数里面需要把原有的指针清空
11 类什么时候必须使用初始化列表来更新变量,而不能采用赋值方法
类中const 类型和引用类型变量,还有需要初始化来设置父类私有变量的子类构造函数。
12 new 和 malloc 区别
new 会调用 构造函数 malloc 不会
delete 会到调用析构函数 free不会
new delete 是运算符号执行更高效 malloc free是函数
new 与 operator new 区别:
- Operator vs function: new is an operator as well as a keyword whereas operator new is only a function.
- New calls “Operator new”: “new operator” calls “operator new()” , like the way + operator calls operator +()
- “Operator new” can be Overloaded: Operator new can be overloaded just like functions allowing us to do customized tasks.
- Memory allocation: ‘new expression’ call ‘operator new’ to allocate raw memory, then call constructor.
13 . c++ 静态成员函数里面不能使用普通成员变量 因为静态成员函数是共享的分不清楚是属于谁的普通成员变量
14 友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加 以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
friend 类型 函数名(形式参数);
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元函数的调用与一般函数的调用方式和原理一致。
若B类是A类的友员类,则B类的所有成员函数都是A类的友员函数
友员类通常设计为一种对数据操作或类之间传递消息的辅助类
15 面向对象子类和父类构造函数析构函数执行顺序:
1、子类对象在创建时会首先调用父类的构造函数
2、父类构造函数执行结束后,执行子类的构造函数
3、当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
4、析构函数调用的先后顺序与构造函数相反
16 构造函数 中调用虚函数不能实现多态
17 函数模板 :在编译的时候会根据不同的类型生成不能的函数,之前引擎里面使用了很多模板导致编译时间很长
18 static_const 除了指针类型不能直接转换
reinterpret_cast<T*>可以在不同类型之前进行转换
19 static 用法
(1)static 申明的变量为静态全局变量,该变量存储在静态数据区,当整个程序结束时该变量才会被释放,只是生命周期延长,作用域不受影响。
(2)static申明的变量定义时如果不初始化默认初始化为0
(3)被static修饰的变量只能作用于本文件内,即使被extern修饰也不能,
20 extern 多个文件中进行声明 不会赋值分配内存,一次赋值分配内存,用于多个文件需要访问但是只是在一个文件中进行初始化赋值的时候,介绍的比较好的文章 https://www.cnblogs.com/yuxingli/p/7821102.html
https://blog.youkuaiyun.com/paxis0813/category_8016917.html
总结:extern 与 static 功能正好相反,static 只能在本编译单元有效。
const 与 static 功能基本相同。但是const 可以与extern 一块适用。
21 volatile 关键字作用防止编译器优化造成不必要的错误,使得volatile修饰的变量都不是从寄存器而是从内存读取 https://www.youkuaiyun.com/gather_21/MtzaIgwsNzItYmxvZwO0O0OO0O0O.html
22 new 、operator new、 placement new 区别
new 调用到时候 执行的过程是
1 先分配内存(调用 operator new)
2 调用构造函数
operator new 可以被重载
placement new 像是operator new 的重载的一个版本一样,但是他不分配内存,它返回的指向已经分配好的内存。
23 c++ 中 全局类变量 静态变量(编译器分配内存) 等会优先于 main 函数执行或者初始化
24 std::move 与 std::forward 的区别与使用
移动构造函数才会造成对象的转移,而move 和forward 都不会。
左值引用和右值引用都是属于引用,修改引用值都会对原值造成影响。
const 左值引用 可以绑定 右值。
右值引用出现的原因:
1 为了解决 大的对象进行转移资源,造成的需要分配内存问题,通过右值引用可以转移资源。
2 给右值的引用生命力,可以修改右值。有了右值引用,不用const 也能绑定右值了,std::move 作用可以把左值引用变成右值引用方便进行转移。
std::move 并不会把值移走,而是会实现了右值引用。 std::move 的作用是让调用构造函数的时候告诉编译器去选择移动构造函数。
td::forward 与 std::move 的区别是,move 会无条件的将一个参数转换成右值, 而 forward 则会保留参数的左右值类型
std::forward 可以用来解决 智能指针赋值时候引用计数会增加1个的问题。
25 RAII 资源获取即初始化
Resource Acquisition Is Initialization (RAII) is a C++ technique where you wrap a class around a resource (file, socket, database connection, allocated memory, ...). The resource is initialized in the class constructor and cleaned up in the class destructor. This way you are sure to avoid resource leaks. More information。