0%

C++ 乱七八糟

const

  • const 是常量的意思,被其修饰的变量不可修改
  • 如果是类、结构体(的指针), 其成员也不不可以更改
  • const 修饰的的是其右边的内容

常引用

  • 引用可以被 const 修饰, 这样就无法通过引用修改数据了,可以称为常引用
  • const 必须写在 & 符号左边,才能算是常引用

const 引用的特点

  • 可以指向临时数据(常量、表达式、函数返回值等)
  • 可以指向不同类型的数据
  • 作为函数参数时(此规则也适用于const指针)
  1. 可以接受 const const实参 (非const引用,只能接受非const实参)
  2. 可以跟非 const 引用构成重载
  • 当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量

初始化列表

只能用在构造函数中

1
2
3
4
5
6
7
class Person {
public:
int m_age;
int m_height;
Person(int age, int height) : m_age(age), m_height(height) {}
// 按变量地址从低到高依次进行初始化(即上面定义变量的顺序)
};

构造函数的互相调用

构造函数调用构造函数必须写到初始化列表里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Person {
int m_age;
int m_height;
Person() : Person(20, 30) {
//Person(0, 0); //ERROR //创建了一个临时的 Person对象
run();
}
Person(int age, int height) {
m_age = age;
m_height = height;
}
void run() {

}
};

父类的构造函数问题

子类的构造函数会默认先调用父类的无参构造函数(析构函数后调用父类的析构函数)
如果子类的构造函数显式地调用父类有参的构造函数,就不再用默认调用父类无参的构造函数
如果父类缺少无参构造函数,子类的构造函数必须显式调用父类有参构造函数

1
2
3
4
5
6
7
8
9
10
class Person {
int m_age;
public:
Person(int age) : m_age(age) {}
};
class Student : Person {
int m_no;
public:
Student(int age, int no) : m_no(no), Person(age) {}
};

父类指针,子类指针

父类指针可以指向子类对象,是安全的,开发中经常用到(继承方式位public)
子类指针指向父类对象是不安全的

1
2
3
4
5
6
7
8
struct Person {
int m_age;
};
struct Student : Person {
int m_score;
};
Person * p = new Student(); //correct
Student *p = new Person(); // error

const 成员

const 成员: 被const 修饰的成员变量、非静态成员函数
const 成员变量

  • 必须初始化(类内部初始化),也可以在声明的时候直接初始化赋值
  • 非static 的 const 变量还可以在初始化列表中初始化

const 成员函数(非静态)

  • const 关键字写在参数列表后面,函数的实现和声明必须带const
  • 内部不能修改staitc 成员变量
  • 内部只能调用const 成员函数、static 成员函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    class Car {
    public:
    const int m_price;
    static int haha;

    void run() const {
    cout << "run" << endl;
    haha = 0;
    //m_price = 0; // error
    }
    };

引用类型成员

引用类型成员变量必须初始化

  • 在声明的时候初始化
  • 通过初始化列表初始化
    1
    2
    3
    4
    5
    6
    7

    class T {
    int age;
    int& m_price;
    public:
    T(int& price) : m_price(price) {};
    };

    对象类型的参数和返回值

  • 使用对象类型作为函数的参数和返回值,可能会产生一些不必要的中间对象

匿名对象(临时对象)

没有变量名、没有被指针指向的对象,用完后马上调用析构

隐式构造 explicit

  • C++中存在隐式构造的现象:在某些情况下,会隐式调用 单参数 的构造函数
  • 可以通过关键字 explicit禁止掉隐式构造
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    #include <iostream>
    using namespace std;

    class Person {
    int m_age;
    public:
    Person() {
    cout << "Person() - " << this << endl;
    }
    Person(int age) : m_age(age){
    cout << "Person(int) - " << this << endl;
    }
    Person(const Person& person) {
    cout << "Person(const Person & person) - " << this << endl;
    }
    ~Person() {
    cout << "~Person()- " << this << endl;
    }
    void display() {
    cout << "display() - age is " << this->m_age << endl;
    }
    };

    void test1(Person person) {

    }

    Person test2() {
    return 40;
    }

    int main() {
    Person p1 = 20; //等价于 Person p1(20);

    test1(30);
    test2();

    return 0;
    }

友元

  • 友元包括友元函数和友元类
  • 如果将函数A(非成员函数)声明为类C的友元函数,那么在函数A就直接能访问类C的所有成员
  • 如果将类A声明类C的友元类,那么在类A所有的成员函数内部都能访问类C对象的所有成员
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <cstring>
using namespace std;

class Point {
friend Point add(Point, Point );
friend class Math;
//friend class Math::add(Point, Point);//error
int m_x;
int m_y;
public:
int getx() {
return m_x;
}
int gety() {
return m_y;
}
Point(int x, int y) : m_x(x), m_y(y) {};
void display() {
cout << m_x << ' ' << m_y << endl;
}
};

class Math {
public:
Point add(Point p1, Point p2) {
return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
void test() {
Point p1(10, 30);
p1.m_x = 10;
p1.m_x;
}
};

// 四次调用get() 效率太低
//Point add(Point p1, Point p2) {
// return Point(p1.getx() + p2.getx(), p1.gety() + p2.gety() );
//}

Point add(Point p1, Point p2) {
return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y );
}
int main() {
Point p1(10, 20);
Point p2(20, 30);
Point p3 = add(p1, p2);
p3.display();

Point p4 = Math().add(p1, p2);
p4.display();

return 0;
}

内部类

  • 如果将类A定义类C的内部,那么类A就是一个内部类(嵌套类)
  • 内部类的特点
  1. 支持publicprotectedprivate权限
  2. 成员函数可以直接访问其外部类对象的所有成员(反过来不行啊)
  3. 成员函数可以直接不带类名、对象名访问外部类的 static成员
  4. 不会影响外部类的内存布局
  5. 可以在外部类内部定义,在外部类外部定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <cstring>
using namespace std;

class Person {
private:
static int m_age;
static void test() {

}
/*void test() {
Car car;
car.m_price = 10; //error

}*/
public:
class Car {
int m_price;
void run() {
Person person;
person.m_age = 10; //成员函数可以直接访问其外部类对象的所有成员
}
};
};

int main() {


return 0;
}
  • 内部类声明和实现分离

局部类

  • 在一个函数内定义的类
    特点:
  1. 作用域仅限于函数内部
  2. 其所有成员必须定义在类里面,不允许使用 static变量
  3. 成员函数不能直接访问函数的局部变量(static变量除外)
求大佬赏个饭