C/C++的一些知识点 一些内容经常会被遗忘 现在就不定时的记录下来

关键字


explicit(Explicit Call to a Constructor)

明确不希望被 隐式调用(Implicit Call to a Constructor)

class Test1
{
public:
    Test1(int n)
    {
        num=n;
    }//普通构造函数
private:
    int num;
};
class Test2
{
public:
    explicit Test2(int n)
    {
        num=n;
    }//explicit(显式)构造函数
private:
    int num;
};
int main()
{
    Test1 t1=12;//隐式调用其构造函数,成功
    Test2 t2=12;//编译错误,不能隐式调用其构造函数
    Test2 t2(12);//显式调用成功
    return 0;
}

volatile

为什么要用volatile

编译器发现2次从n读数据的代码之间 没有对n进行过操作 就会自动使用上次读的数据

如果加上volatile 就相当于告诉编译器 访问该变量时不再进行优化 从而能够稳定的访问变量n

什么情况下会出现这类问题

1.汇编代码修改变量

#include <stdio.h>
void main()
{
    int i = 10;		--> volatile int i = 10;
    int a = i;

    printf("i = %d\n", a);

    // 下面汇编语句的作用就是改变内存中 i 的值
    // 但是又不让编译器知道
    __asm 
    {
        mov dword ptr[ebp - 4], 20h
    }

    int b = i;
    printf("i = %d\n", b);
}

当关闭优化时 正确输出

i = 10
i = 32

开启优化时(O2…) 则输出

i = 10
i = 10

如果i使用volatile修饰符时 皆正确输出

i = 10
i = 32

2.多线程下对变量的修改 变量 stop

volatile bool stop = false;

线程1中:

while(!stop) {...}
printf("stop!");

线程2中:

stop = true

线程2后启动与线程1 若stop不加volatile 线程1将是死循环

面向对象


面向对象

封装 继承 多态

C++构造函数和析构函数是否可以为virtual

构造函数不行 析构函数可以

原因是虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的 而在构造函数完成前 虚函数表尚未创建 虚函数及虚函数表可以通过C++虚函数表解析进行深入了解

为什么要求具有层次结构的顶级类定义其析构函数为虚函数

Class A
{
public:
    A(){}
    ~A(){printf("~A\n");}		--> virtual ~A(){printf("v ~A\n");}
};
Class B: public A
{
public:
    B(){}
    ~B(){printf("~B\n");}
}

A* a = new B();
delete a;

派生类的成员需要析构等操作时 需要调用对应的析构代码 通过对析构函数设为虚函数的方式 使得类逐层进行析构(同时也是为了防止内存泄漏)

如果析构函数非虚函数 调用的析构函数依赖于指向的静态类型

析构函数为虚函数时 输出:
~B
v ~A

析构函数非虚函数时 输出:
~A

虚函数的常见问题

1.构造函数不能是虚函数

2.析构函数可以是虚函数(甚至是纯虚函数) 具有层次结构的顶级类中往往是必须的

3.将一个函数定义为纯虚函数 则为抽象类 不能生成对象 若要使派生类为非抽象类 必须实现虚函数的函数体(一旦实现 此时纯虚函数变为虚函数)

4.派生类的override虚函数定义必须和父类完全一致 除了一个特例 如果父类中返回值是一个指针或引用 子类override时可以返回这个指针(或引用)的派生


未完待续…