C++学习笔记:extern “C”的用法及众多基础知识
extern “c”的用法:都是在c++编译时,让部分代码按照c编译器的解释来编译。
可以修饰一个函数,
extern "c" int initializewinsockifnecessary();
也可以修饰一大段(通常是我们自己写的代码,c语言的):
#ifdef __cplusplus extern "c" { #endif .... #ifdef __cplusplus } #endif
下面两种形式的区别?
#include #include "file.h"
答:前者是从标准库路径寻找和引用file.h(找不到也不去当前路径找,也可以写成一个绝对路径但不好),而后者是从当前工作路径搜寻并引用file.h。
const 有什么用途?
答:在c/c++中,(1)可以定义const常量,(2)修饰函数的返回值和形参;
这里说修饰函数返回值,场景是返回引用的时候,不希望调用方修改返回值。
在c++中,还可以修饰函数的定义体,定义类的const成员函数。被const修饰的东西受到强制保护,可以预防意外的变动,提高了程序的健壮性。
const和#define有什么区别?
都可以定义常量,但define是预编译时展开的。因此const在对变量进行类型检查以及调试时都更好用。
sizeof对于c++还有一些要注意:
一个空类占1个字节,单一继承的空类占1个字节,虚继承涉及到虚指针所以占4个字节
sizeof不计算static变量占得内存(应该是计算类的size时不计算类中的static)。
指针和引用的区别?
答:指针和引用都提供了间接操作对象的功能。
(1) 指针定义时可以不初始化,而引用在定义时就要初始化,和一个对象绑定,而且一经绑定,只要引用存在,就会一直保持和该对象的绑定;
(2) 赋值行为的差异:指针赋值是将指针重新指向另外一个对象,而引用赋值则是修改对象本身;
(3) 指针之间存在类型转换,而引用分const引用和非const应用,非const引用只能和同类型的对象绑定,const引用可以绑定到不同但相关类型的对象或者右值。
空指针和悬垂指针的区别?智能指针?
答:空指针是指被赋值为null的指针;指向动态分配对象的指针,在对象被释放后,将会产生悬垂指针。
空指针可以被多次delete,而悬垂指针再次删除时程序会变得非常不稳定;
使用空指针和悬垂指针都是非法的,而且有可能造成程序崩溃,如果指针是空指针,尽管同样是崩溃,但和悬垂指针相比是一种可预料的崩溃(如果指针被释放但没有赋值为null,则称作野指针)。
避免悬垂指针可利用智能指针,就是给对象加个引用计数,初始化的时候置1,最后一次解引用才释放。
c++中有malloc/free,为什么还有new/delete?
由于malloc/free是库函数而不是运算符,不在编译器控制之内,不能把执行构造函数和析构函数的任务强加给它,因此,要完成对象的初始化和析构过程,c++还需要new/delete。
面向对象技术的基本概念是什么,三个基本特征是什么?
答:基本特征:封装、继承、多态。
c++空类默认有哪些成员函数?
默认构造函数
析构函数
拷贝构造函数
赋值运算符(operator=)
取址运算符(operator&)(一对,一个非const的,一个const的)
当然,所有这些只有当被需要才会产生。比如你定义了一个类,但从来没定义过该类的对象,也没使用过该类型的函数参数,那么基本啥也不会产生。在比如你从来没有进行过该类型对象之间的赋值,那么operator=不会被产生。
17-27没看,本文最下面复制了一下。
main函数执行之前会执行什么?执行之后还能执行代码吗?
1.全局对象的构造函数会在main函数之前执行。
2.可以用atexit()注册一个或多个函数退出清理函数,它们按照注册时的反顺序,在exit()或return时被调用。(或者on_exit()但这个函数不建议用。)
#include int atexit(void (*function)(void)); //return 0 on success.
注意,fork子进程时,这些函数会被继承到子进程。而exec系列执行成功后,所有函数会被清空。
#include void exit(int status);
exit()将进程正常退出,并将(status & 0377)返回到父进程的wait(),status可以是exit_success或exit_failure。
exit()会按出栈顺序(反序)依次调用atexit()/on_exit()注册的函数。然后将所有打开的stdio流进行flush并关闭,通过tmpfile()创建的文件也被删除。那么,如果某个清理函数中调用_exit()或把自己kill结果退出了,后续清理函数以及刷stdio就不会执行了。
如果子进程exit()了,会发送一个sigchld信号给父进程,如果父进程设置了sa_nocldwait,那这个信号是否发送是未定义的。
如果子进程exit(),父进程在等待(wait()系列函数)子进程的状态,或者父进程设置了sa_nocldwait或者将sigchld的处理置为sig_ign,子进程都会立即退出。而如果父进程既没有wait,又没有设置忽略子进程退出,子进程就会变成僵尸进程(除了一个字节的exit status,什么都没有),等以后父进程wait的时候仍能拿到status。
这里也说下exit()和_exit()的区别,_exit()让程序“立即”退出,它不会调用上述atexit()/on_exit()注册的函数。它关闭自己打开的所有文件描述符,但是否flush stdio以及是否删除tmpfile创建的文件是与具体实现相关的(即没有明确规定)。
#include void _exit(int status);
当然,_exit()会关闭文件描述符,所以可能也会有些delay(例如还没写完就close),如果想达到“立即”的目的,可以在_exit()之前调用一下tcflush()可能会有帮助。
—–没试验start—-
static数据成员和static成员函数
答:static数据成员:
static数据成员独立于该类的任意对象而存在;每个static数据成员是与类关联的对象,并不与该类的对象相关联。static数据成员(const
static数据成员除外)必须在类定义体的外部定义。不像普通数据成员,static成员不是通过类的构造函数进行初始化(不能放在初始化列表中),而是应该在定义时进行初始化。
static成员函数:
static成员函数没有this形参,它可以直接访问所属类的static成员,不能直接使用非static成员。因为static成员不是任何对象的组成部分,所以static成员不能被声明为const。同时,static成员函数也不能被声明为虚函数。
多态类中的虚函数表是 compile-time,还是 run-time时建立的
答案:虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组。而对象的隐藏成员–虚拟函数表指针是在运行期–也就是构造函数被调用时进行初始化的,这是实现多态的关键。
一个父类写了一个 virtual 函数,如果子类覆盖它的函数不加 virtual ,也能实现多态在子类的空间里,有没有父类的这个函数,或者父类的私有变量
答案:只要基类在定义成员函数时已经声明了virtual关键字,在派生类实现的时候覆盖该函数时,virtual关键字可加可不加,不影响多态的实现。子类的空间里有父类的所有变量(static除外)。
—–没试验end—-
内联函数在编译时是否做参数类型检查?
答:内联函数要做参数类型检查, 这是内联函数跟宏相比的优势。
有1,2,….一直到n的无序数组,求排序算法,并且要求时间复杂度为o(n),空间复杂度o(1),使用交换,而且一次只能交换两个数。
答:很明显,使用桶式排序,空间复用原数组的下标。
======================
17.继承层次中,为什么基类析构函数是虚函数?
答:编译器总是根据类型来调用类成员函数。但是一个派生类的指针可以安全地转化为一个基类的指针。这样删除一个基类的指针的时候,c++不管这个指针指向一个基类对象还是一个派生类的对象,调用的都是基类的析构函数而不是派生类的。如果你依赖于派生类的析构函数的代码来释放资源,而没有重载析构函数,那么会有资源泄漏。
18.为什么构造函数不能为虚函数?
答:虚函数采用一种虚调用的方法。需调用是一种可以在只有部分信息的情况下工作的机制。如果创建一个对象,则需要知道对象的准确类型,因此构造函数不能为虚函数。
19.如果虚函数是有效的,那为什么不把所有函数设为虚函数?
答:不行。首先,虚函数是有代价的,由于每个虚函数的对象都要维护一个虚函数表,因此在使用虚函数的时候都会产生一定的开销,这是没有必要的。
20.构造函数可以是内联函数
21.什么是多态?多态有什么作用?
答:多态就是将基类类型的指针或者引用指向派生类型的对象。多态通过虚函数机制实现。
多态的作用是接口重用。
22.重载和覆盖有什么区别?
答:虚函数是基类希望派生类重新定义的函数,派生类重新定义基类虚函数的做法叫做覆盖;
重载就在允许在相同作用域中存在多个同名的函数,这些函数的参数表不同。重载的概念不属于面向对象,编译器根据函数不同的形参表对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。
重载的确定是在编译时确定,是静态的;虚函数则是在运行时动态确定。
23.公有继承、受保护继承、私有继承
答:
(1)公有继承时,派生类对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有和受保护成员;
(2)私有继承时,基类的成员只能被直接派生类的成员访问,无法再往下继承;
(3)受保护继承时,基类的成员也只被直接派生类的成员访问,无法再往下继承。
24.公有继承时基类受保护的成员,可以通过派生类对象访问但不能修改。
25.有哪几种情况只能用构造函数初始化列表而不能用赋值初始化?
答:const成员,引用成员
26.什么是虚指针?
答:虚指针或虚函数指针是虚函数的实现细节。带有虚函数的每一个对象都有一个虚指针指向该类的虚函数表。
27.c++如何阻止一个类被实例化?一般在什么时候将构造函数声明为private?
答:(1)将类定义为抽象基类或者将构造函数声明为private;
(2)不允许类外部创建类对象,只能在类内部创建对象