C++整理

静态:

(1)类静态数据成员在编译时创建并初始化,属于类,不属于某个对象,为所有对象所共享,包括该类派生类的对象,可以通过类名or对象访问。

(2)static成员变量,可以实现同类对象间的信息共享。存储在数据段(data-rw){全局变量也是存储在data区},故而计算类大小时,不将其计算在内。

  (3) static成员可以产业能够为成员函数的可选参数{可选参数必须放在参数表的最右边},普通数据成员则不可以。

  

1 void fun(int a,int b,int c=10);
2     fun(1,2); //a=1,b=2,c=10
3 
4 void fun(int a,int b=10,int c);
5     fun(1,2); //a=1,b=? c=?
class base
{
public:
  static int static_var;
  int var;
  void foo1(int i=staitc_var);//正确
  void foo2(int i=var);//错误
}

(4)数据成员的类型和初始化方式:/cite https://www.nowcoder.com/questionTerminal/b73db04e98174120b50b5478839b3f8f?orderByHotValue=1&mutiTagIds=569&page=1&onlyReference=false

static成员  初始化在类外,且不加static修饰
const成员 只能在构造函数后的初始化列表中初始化
const static成员 类只有唯一一份拷贝,且数值不能改变。因此,可以在类中声明处初始化,也可以像static在类外初始化

(5)静态成员函数的意义,是在于管理静态数据成员,完成对静态数据成员的封装。因为非静态成员函数,在调用时this指针会被当做参数传入,静态函数成员属于类,不属于对象,无this指针,所以静态函数成员只能访问静态数据成员。

(6)静态成员函数不可以同时声明为virtual,const,volatile函数。

  /cite http://www.jianshu.com/p/a3303c9ba748

       /cite http://www.cnblogs.com/Myhsg/archive/2009/07/31/1535650.html

同步IO和异步IO:

(1)同步IO,发出一个功能调用时,在没有得到结果之前,该调用就不返回。

(2)异步IO,当一个异步调用发出后,通过状态、通知、回调函数来通知调用者。

IOCP:

 (1)IOCP是一个异步I/O的API,可以高效地将I/O事件通知给应用程序。

C/C++内存的申请释放:

(1)malloc、free无法对非内部类型的对象自动执行构造函数、析构函数。

(2)macllo、free是库函数,不是运算符,所以不在编译器控制权限之内。new、delete不是库函数,是运算符,所以拥有执行构造函数、析构函数的权限。

(3)new出来的指针直接带类型信息,malloc返回的是void指针。

指针和引用:

(1)指针是一个变量,引用是一个别名。

(2)引用必须在定义的时候初始化,之后不能改变。

(3)引用不能为空,指针可以为空。

(4)sizeof(指针)为指针本身的大小,sizeof(引用)所指向对象的大小。

(5)不存在多级引用,引用不需要分配内存区域。

多态:

通过虚函数,在子类中通过重写的方式实现多态,实现根据对象的实际类型来调用相应的函数。

(1)存在虚函数的类都有一个一维的虚函数表,类的对象有一个指向虚函数表的虚指针。

(2)抽象类是至少包括至少一个纯虚函数的类。

多态的实现原理:

(1)早期绑定,静态绑定:编译器在编译的时候,需要确定每个对象调用(非虚函数)的地址。

(2)假设存在父类P,父类对指针*pf。子类C,子类对象c。子类和父类具有同名函数say()。当指针pf指向对象c时,通过指针调用say(),会调用父类中的函数。

class P
{
public:  
    void say()
    {
       std::cout<<"I'm father";
    }
}
class C:public P
{
   void say()
   {
       std::cout<<"I'm children";
   }
}
void main()
{
    C c;
    P *pf=&c;
    pf->say();
}

多态实现机制

理解多态首先要理解类对象的内存模型。

子类的对象内存模型是:父类的对象所占内存+子类的对象所占内存,所以当创建子类对象的时候,首先回去调用父类的构造函数,构造出父类的对象后,再调用子类的构造函数完成自身的构造。当将子类对象转换父类对象时,基于安全考虑,编译器会将该对象认为是子类对象模型的上半部分,也就是父类对象。所以使用类型转换后的对象指针调用函数的时候,会调用父类对象的函数。这些都是在编译期间决定的,为了达到对象和函数一一对应的目的,需要使用动态绑定,也就是使用多态。在基类中函数使用virtual关键字,此时子类会自动的在其同名函数上也加上,当然也可以手动添加virtual关键字。编译器会给有virtual关键字的类创建一个虚函数表(vtable){在构造函数中完成虚表的创建},里面以一维数组的形式记录了有virtual关键字的函数地址。为了定位vtable,编译器会给该类的每个对象提供了一个虚函数指针(vptr){在构造函数中完成虚指针的初始化},该指针指向了该对象所属类的vtable。

在程序运行时,会根据对象的类型初始化虚指针{不使用多态特性时,会根据指针/引用类型来调用相关函数},使其指向正确的vtable。虚表可以继承,即使子类中没有重写虚函数,子类仍然具有该函数的地址,如果子类重写了该虚函数,那么新地址会覆盖继承下来的虚表中记录的虚函数原地址,如果子类新增了虚函数,对应的虚函数表中会增加对应项。回顾上文所述的对象内存模型,对象会首先执行父类的构造函数,完成父类对象的构造和父类的虚表和虚指针后,再进行自身的构造。

原文地址:https://www.cnblogs.com/woaixuexiya/p/7769028.html