跳转至

c++ 中的细节点

delete

  • delete处理单个类类型,先会调用析构函数,释放它所占资源,然后释放它所占内存空间。
  • delete处理数组类类型的时候,会对每一个数组对象都调用它们的析构函数,然后再释放它们所占用的内存空间。所以对于类类型的数组如果不调用delete[],那就只调用了下标为0的对象的析构函数,可能会产生问题。

c 语言和c++申请空间和释放的区别

  • new delete 可以触发构造和析构函数,c语言中的malloc,free则不会
#include <iostream>
using namespace std;



int main(int argc, char const *argv[])
{

    // new 申请内存
    int *p1 = new int;  // c++
    *p1 = 12;  // 写
    cout << *p1 << endl;  // 读
    delete p1;  // delete + 指针

    // 申请并初始化
    int *p2 = new int(123);
    cout << *p2 << endl;
    delete p2;

    // 申请数组空间,返回空间的首地址
    int *p = new int[5];
    p[0] = 0;
    p[1] = 1;
    p[2] = 2;
    p[3] = 3;
    p[4] = 4;
    cout << p << endl;
    delete[] p;  // 释放数组要加[]
    return 0;
}

引用

#include <iostream>
using namespace std;



int main(int argc, char const *argv[])
{
    int a = 0;
    int &c = a;  // 声明变量a的一个引用c, 引用的时候一定要赋值
    cout << a << ' ' << c << endl;

    c = 13;
    cout << a << endl;

    // 引用一旦绑定就是唯一的
    int f = 14;
    c = f;  // 把f的值赋值给c,并不是c引用至f,c已经引用于a了
    cout << a << endl;

    // 常量的引用
    const int &aa = 12;
    cout << 12 << endl;

    // 数组的引用
    int arr[12];
    int (&p)[12] = arr;

    // 二维数组的引用
    int arr2[2][3];
    int (&p2)[2][3] = arr2;

    // 指针的引用
    int b = 12;
    int *point = &b;

    int *(&p3) = point;
    *p3 = 23;
    cout << *point << endl;
    return 0;
}

引用和指针的区别

  • 引用声明就要初始化,指针不用。
  • 引用初始化之后就不能引用其他空间,指针可以指向其他空间
  • 引用不占存储空间,指针占空间
  • 引用效率更高,指针间接操作
  • 引用更安全,指针可以偏移
  • 指针更灵活,直接操作地址。

#include <iostream>
using namespace std;


class T
{
public:
    T();
    ~T();

private:
    int a = 0;
};

T::T()
{
}

T::~T()
{
}

int main(int argc, const char* argv)
{
    T* t = new T;  // 栈空间的指针t指向堆空间new出的对象
    T& r = *t;  // 栈空间的引用变量指向new T对象
    T tt = r;  // tt栈空间指向堆空间的new T拷贝出来的对象
    T* t1 = &tt;  // t1指针指向tt指针的地址
    cout << t << endl << &r << endl;
    return 0;
}
参考链接: https://www.zhihu.com/question/37608201

初始化和赋值

#include <iostream>
using namespace std;


int main(int argc, char const *argv[])
{
    int a = 0;  // 初始化
    cout << a << endl;

    int b;
    b = 1;  // 赋值
    cout << b << endl;

    // 数组初始化和赋值
    int arr[5] = {1, 2, 3, 4, 5};  // 初始化
    cout << arr[0] << ' ' << arr[1] << endl;

    int arr2[5];
    arr2[0] = 1;  //赋值
    arr2[1] = 2;
    cout << arr2[0] << ' ' << arr2[1] << endl;

    // 引用: 只能初始化
    int &c = a;
    cout << c << endl;

    // const常量: 只能初始化
    const int d = 100;
    cout << d << endl;
    return 0;
}

初始化的顺序

成员初始化顺序至于声明顺序有关,跟初始化书写顺序无关

#include <iostream>
using namespace std;


class Stu
{
private:
    int a;
    int b;

public:
    Stu(): b(10), a(b)  // 用b的值给a初始化,再把b初始化为10
    {

    }  
    ~Stu(){}
    void show()
    {
        cout << "a:" << a << ' ' << "b:" << b << endl;
    }
};


int main(int argc, char const *argv[])
{
    Stu stu;
    stu.show();  // a:0 b:10
    return 0;
}
#include <iostream>
using namespace std;


class Stu
{
private:
    int a;
    int b;

public:
    Stu(): b(a), a(10)  // a初始化为10,再把b的值初始化为a
    {

    }  
    ~Stu(){}
    void show()
    {
        cout << "a:" << a << ' ' << "b:" << b << endl;
    }
};


int main(int argc, char const *argv[])
{
    Stu stu;
    stu.show(); // a:10 b:10
    return 0;
}

内联函数要注意的点

内联函数和宏定义

#include <iostream>
using namespace std;

#define SUM(x) x*x

inline int func(int x)
{
    cout << "func:" << x * x << endl;
    return 0;
}

int main(int argv, const char* argc)
{
    cout << "SUM:" << SUM(2 + 3) << endl;  // 2+3 * 2+3 = 11
    func(2+3);  // (2+3) * (2+3) = 25
    return 0;
}

结论: 宏定义是单纯的变量替换。

类与内联函数

  • 类内定义,不论加不加inline 都是内联函数
  • 类外定义,有inline是内联,没用不是内联

内联函数和头文件

  • 内联函数可以有多个定义,多个定义必须完全一致
  • 所以通常情况下,内联函数写在头文件里,

联编

模块或者函数合并在一起生成可执行代码的过程。

按照联编所进行的阶段不同,可分为静态联编,动态联编

动态联编是针对c++多态的, C语言里全部都是静态联编.

#include <iostream>
using namespace std;

class A
{
public:
    A() {}

    ~A() {}
    // 虚函数 是在基类中使用关键字 virtual 声明的函数。
    // 在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
    virtual void func()  
    {
        cout << "A func" << endl;
    }
};

class B: public A
{
public:
    B() {}
    ~B() {}
    void func()
    {
        cout << "B func" << endl;
    }
};


int main(int argv, const char* argc)
{
    A* a = nullptr;
    int b;
    cin >> b;
    switch (b)
    {
    case 1: a = new A; break;
    case 2: a = new B; break;
    default:
        break;
    }
    a->func();
}