C++学习

1、C++中引用和指针的区别
指针保存的是一个对象的地址,引用是这个对象的别名。
int a = 1;
int * p = &a;
这里变量a和指针p本身地址是不一样的。

int a = 1;
int &b = a;
这里变量a和引用变量b的地址是一样的,两个变量指向同一个内存地址。

主要区别:
引用变量不能为空,在定义时必须初始化。
引用变量初始化后,引用的对象不能再改变。b引用了a后,不能再引用c变量。

总结:
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名,引用不改变指向。

指针和引用作为函数参数进行传递时的区别:
传值调用、传址调用、引用调用中传址调用、引用调用都可以改变传入的实参的值。
区别在于指针调用也是将指针变量的值(所指向变量的地址的拷贝)传入形参,在函数内修改所指向变量的值。
引用调用直接把实参传入了函数内,修改了形参就修改了实参。

2、__cdecl和__stdcall区别
两者的区别是清栈方式不同,如果使用__stdcall由函数自己清栈,如果使用__cdecl由调用者自己清栈。

当函数参数个数不定时,只能使用__cdecl来说明函数的调用方式。
如:int sprintf(unsigned char *out, const unsigned char *format, …)

3、类中的静态变量和静态函数
类中的静态变量是属于类的不属于某个对象,它是所有对象所共用的。
静态数据成员需要单独初始化:
<数据类型><类名>::<静态数据成员名>=<值>

静态成员函数可以使用静态数据成员,非静态数据成员要通过具体对象来引用(因为静态成员函数没有this指针)。
静态成员函数主要为了调用方便,不需要生成对象就能调用。

4、类中的常数据成员和常成员函数
1)常数据成员,只能通过构造函数的参数初始化表对常数据成员进行初始化。
3)常成员函数不能修改类的数据成员。
2)常对象只能调用常成员函数。

5、回调函数
回调函数是用函数指针作为参数进行函数调用的一种过程,是函数指针的一种用法。
你要调用某个函数,这个函数一部分功能需要由调用者来实现,那么就传入一个自己的函数的地址,在这个函数内执行自己的函数,相当于在别人的函数里嵌套了自己的函数。

使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中(自己的函数)处理消息或完成一定的操作。

另外一种回调函数,是比如Win32 API中的窗口处理函数:

LRESULT CALLBACK WndProc( HWND hWnd, // 窗口的句柄
                              UINT nMsg, // 消息的ID号
                              WPARAM wParam, // 消息所对应的参数
                              LPARAM lParam) // 消息所对应的参数

窗口处理函数由系统定义,用户来实现,由系统函数间接调用。

6、C++中this指针
当在一个对象的成员函数中要调用这个对象的其它函数时,用this指针表示这个对象,this->其它成员函数。
this指针记录每个对象的内存地址,然后通过运算符->访问该对象的成员。

7、C++中私有成员函数如何访问
属性是私有的,类的对象实例不能直接调用私有成员函数,要在其它成员函数内调用。

8、protected 保护成员和保护继承
在没有继承的情况下,protected跟private相同。在派生类的时候才出现分化。
protected可以被该类的方法和其友元函数访问,但不能被该类的对象访问。

保护继承
派生类的成员函数,可以访问基类的公有成员和保护成员。
派生类的对象,不能访问基类的所有成员。

9、私有继承和保护继承
私有继承
派生类的成员函数,可以访问基类的公有成员和保护成员。
派生类的对象,不能访问基类的所有成员。

从中可以看出,私有继承和保护继承规则似乎是一样的,它们有什么区别呢?
私有继承的作用是让某个类不能被多次继承
A类 -> B类 -> C类
B类私有继承A类,C类又公有继承B类,但是此时C类继承不到A类的公有成员和保护成员。

10.0
静态束定
在编译时就决定了程序的调用。

动态束定
编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序执行时才能确定将要调用的函数。

10.1、虚函数
动态束定用虚函数来实现。
virtual <类型说明符> <函数名> (<参数表>)
指向基类的指针或引用,在操作它的派生类对象时,会根据不同的类对象,调用其相应的派生类中同名函数,这个函数就是虚函数。

构造函数中调用虚函数,采用静态联编即构造函数调用的虚函数是自己类中实现的虚函数,如果自己类中没有实现这个虚函数,则调用基类中的虚函数。
析构函数中调用虚函数同构造函数一样,即析构函数所调用的虚函数是自身类中的或者基类中实现的虚函数。

11、纯虚函数
virtual <类型说明符> <函数名> (<参数表>)=0;

class A
{
  public:
    A();
    void f1();  //普通成员函数
    virtual void f2();  //虚函数
    virtual void f3()=0;  //纯虚函数
    virtual ~A();
};

纯虚函数是在基类中声明的虚函数,它可以在基类中有定义,而且派生类必须定义自己的实现方法,重写虚函数。

12、抽象类
带有纯虚函数的类就是抽象类,抽象类不能定义对象。

13、虚析构函数
虚析构函数是为了解决,当基类的指针指向派生类对象,并用基类的指针删除派生类对象时,不会调用派生类的析构函数。
这样会造成派生类对象的内存泄漏。
当说明基类的析构函数是虚函数时,会先调用派生类的析构函数,再调用基类的析构函数,动态束定。
PS:10.0、10.1、11、12、13小点都是和多态有关