Basic

C++继承了C语言的高效、简洁、快速和可以执行,同时融合了三种不同的编程方式:

  • C语言代表的过程性语言

  • 在C语言基础上添加的类代表的面向对象语言

  • C++模板支持的泛型编程

C & C++

  • C是面向过程,C++是面向对象

    • C++添加了类

  • C++有引用的概念,C没有

  • C变量只能在函数的开头处声明和定义,而C++随时定义随时使用

int & new int()

#include <iostream>

using namespace std;

int main() {
    int *a = new int(1);
    cout<<a<<endl<<*a<<endl;
    while (true) {
        new int(1);
    }
}

// 上面这段代码有内存泄露的问题
// 下面的不会

#include <iostream>

using namespace std;

int main() {
    int *a = new int(1);
    cout<<a<<endl<<*a<<endl;
    while (true) {
        // new int(1);
        int b = 1;
    }
}

new/delete & malloc/free

使用

//// malloc
// 原型
void * malloc(size_t size);
// 使用
int *p = (int *) malloc(sizeof(int) * length);

//// new
int *array = new int[5];

//// free
free(p);    // 不用指定长度

//// delete
delete[] array
delete p

项目

new/delete

malloc/free

属性

C++关键字/操作符,需要编译器支持

库函数,需要头文件支持

参数

无须指定内存块的大小,编译器会根据类型信息自行计算

需要显式地指出所需内存的尺寸

返回类型

返回对象类型的指针,无需转换

返回void*指针,需要强转

分配失败

抛出bas_alloc异常

返回NULL

其他

  • new运算符内部数据类型不进行初始化,会自动调用非内部数据类型的默认构造函数

  • 由于 malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加malloc/free

new/delete VS malloc/free

  • new/delete 是关键词;malloc/free是库函数

  • new/delete会调用对象构造/析构函数

delete VS delete[]

  • 对于内建简单数据类型,delete和delete[] 相同

  • 对于复杂数据类型,delete[]删除一个数组

构造函数与析构函数调用

  • 构造对象时,先调用父类构造函数,再调用派生类构造函数

  • 析构对象时,先调用派生类析构函数,再调用基类构造函数

const用途

  • 定义只读变量,即常量

  • 修饰函数的参数和函数的返回值

  • 修饰函数的定义体,这里的函数为类的成员函数,被const修饰的成员函数代表不修改成员变量的值

指针和引用

  • 引用是变量的一个别名,内部实现是只读指针,仍然占用栈空间,但是地址和被引用的变量一致,这说明编译器隐藏了引用变量的地址

  • 有多级指针,但没有多级引用

  • 引用只能在初始化时被赋值,其他时候值不能被改变,非const指针的值可以在任何时候被改变

  • 引用不能直接赋值为NULL,指针可以

    int *p = nullptr;
    int &r = nullptr; <--- compiling error
    int &r = *p;  <--- likely no compiling error, especially if the nullptr is hidden behind a function call, yet it refers to a non-existent int at address 0
  • 引用变量内存单元保存的是被引用变量的地址

  • "sizeof 引用" = 指向变量的大小 , "sizeof 指针"= 指针本身的大小

  • 指针可以指向栈和堆空间,但是指引用地址只能是栈

  • 指针可以使用++或+n遍历数组

  • 指针拥有一个内存地址,引用的内存地址和被引用变量一致

  • const引用可以绑定临时变量,但是指针不可以

    const int &x = int(12); //legal C++
    int *y = &int(12); //illegal to dereference a temporary.

include <> & ""

  • #include <...> : 首先搜索默认路径,如果不存在,再去搜索源文件所在目录

  • #include "..." : 首先搜索源文件所在目录,如果不存在,再去搜索默认路径

  • PS

    • 默认路径 : 系统及LD_LIBRARY_PATH定义路径

共享/动态库和静态库

  • 共享库/动态库(Shared libraries / Dynamic libraries)

    • .so or .dll in windows or .dylib in OS X

    • 在程序运行时使用它

    • 使用共享库的程序仅引用使用到的代码

    • 优点

      • 编译的程序较小

      • 可以在不重新编译程序的前提下,更新动态库

    • 缺点

      • 增加运行时开销

  • 静态库(Static libraries)

    • .a or .lib in windows

    • 在编译时直接链接到程序中

    • 使用静态库的程序从静态库中获取它使用的代码的副本,并使其成为程序的一部分

  • 打包动态库/静态库

限定词

static

作用

  • 修饰全局

  • 程序运行分配内存,生命周期和程序一样

class A {
public:
    // static int a = 1;            // ERROR: ISO C++ 禁止在类内初始化非 const static 成员变量
    const int b = 1;            
    const static int c = 1;         // OK
    // const static double d = 1.1; // ERROR: 禁止在类内初始化非整形 const static 成员变量
    const int e;                    // WARNING: 必须初始化; 这里 OR 构造函数初始化列表
    const double f = 1.1;
    A () : e(1) {
        // e = 3;                   // 常量不可赋值 必须在定义时初始化
    }

    void fc (int v) {
        const int fc = v;
        const static int fcs = v;
        cout << fc << endl;
        cout << fcs << endl;
    }
};

int main() {
    A a;
    a.fc(1);
    A b;
    b.fc(2);
    return 0;
} /** Output
1
1
2
1
*/

const vs static

  • const : 不可更改

  • static : 静态常量

  • const static : 不可变的静态变量

Struct & Class

struct in c VS struct in c++

特殊语法

临时对象的产生和运用

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template <class T>
void print(const T& v) {
    cout << v << " ";
}

template <class T>
class Print {
public:
    void operator()(const T& v) {
        cout << v << " ";
    }
};

int main() {
    int val[] = {0, 1, 2, 3, 4, 5, 6};
    vector<int> vec(val, val+7);
    for_each(vec.begin(), vec.end(), print<int>);
    cout << endl;
    for_each(vec.begin(), vec.end(), Print<int>());    // Print<int>() 是一个临时对象
    cout << endl;
    return 0;
}

/** Output
0 1 2 3 4 5 6 
0 1 2 3 4 5 6 
*/

静态常量整数成员可在class内部直接初始化

#include <iostream>

using namespace std;

class A {
public:
    static const int a = 1;
    // static int f = 1;    // ISO C++ forbids in-class initialization of non-const static member 'A::f'; 非const static int, 必须类外定义
    // static const double b = 1.1; // constexpr' needed for in-class initialization of static data member 'const double A::b' of non-integral type
    static const double c;
    // static const string d = "d"; // in-class initialization of static data member 'const string A::d' of non-literal type
    static const string e;
};

const double A::c = 1.2;
// const static double A::c = 1.2;  // may not be used when defining (as opposed to declaring) a static data member
const string A::e = "e";

int main () {
    return 0;
}

不仅只是int,整数类型都可以

  • char

  • long

  • ...

操作符重载

#include <iostream>

using namespace std;

class INT {
private:
    int m_i;
    friend ostream& operator<<(ostream& os, const INT& i);
public:
    INT(int i) : m_i(i) {}

    INT& operator++ () {
        ++(this->m_i);
        return *this;
    }

    const INT operator++(int) {
        INT temp = *this;
        ++(*this);
        return temp;
    }

    INT& operator--() {
        --(this->m_i);
        return *this;
    }

    const INT operator--(int) {
        INT temp = *this;
        --(*this);
        return temp;
    }

    int& operator*() const {    // ? 将const int 转为non-const lvalue
        return (int&)m_i;
    }

    void operator()() const {   // 如果不加const, 对于 const INT 无法使用该操作符
        cout << m_i << endl;
    }

};

ostream& operator<<(ostream& os, const INT& i) {
    os << '[' << i.m_i << ']';
    return os;
}

int main() {
    INT I(5);
    cout << I << endl;
    I();
    (I++)();
    (++I)();
    cout << I << endl;
    (I--)();
    (--I)();
    cout << *I << endl;
    return 0;
}

/** Output
[5]
5
5
7
[7]
7
5
5
*/

C++没有finally语句怎么释放资源

使用C/C++的人,都该有这么一个共识:对资源谁申请谁释放,否则就必须使用委托。当资源仅在某一个函数里使用时,那就必须在该函数里释放。

在C++中通常使用RAII,即Resource Aquisition Is Initialization。就是将资源封装成一个类,将资源的初始化封装在构造函数里,释放封装在析构函数里。要在局部使用资源的时候,就实例化一个local object。在抛出异常的时候,由于local object脱离了作用域,自动调用析构函数,会保证资源被释放。

最后更新于

这有帮助吗?