cpp

引用

别名引用

别名引用实质就是一个常量指针 Type& variable == Type* const variable

1
2
3
4
5
6
7
8
9
10
11
int main(int argc, const char * argv[]) {
int a = 10;
int &b = a;

a = 20;

std::cout << "a: " << a << std::endl; //20
std::cout << "b: " << b << std::endl; // 20

return 0;
}

引用可做函数返回值

1
2
3
4
5
6
7
8
9
10
11
int& getA() {
static int a = 1;
cout << "a: " << a << endl;
return a;
}

int main(int argc, const char * argv[]) {
getA() = 10;
getA() = 100;
return 0;
}

常量引用

const Type& variable == const Type* const variable

1
2
3
4
5
6
7
8
9
10
int main(int argc, const char * argv[]) {
int a = 1;
const int &b = a;
const int &c = 1;
a = 10;
// b = 100; //报错
cout << "a: " << a << " b: " << b << " c:" << c << endl;

return 0;
}

函数

inline内联函数

inline函数可以减少函数进栈出栈所消耗的性能, 一般用于一些简单的逻辑

define与inline函数的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define FUNC(a, b) ((a) < (b) ? (a) : (b))
inline int FUNC2(int a, int b) {
return a < b ? a : b;
}

int main(int argc, const char * argv[]) {
int a = 1;
int b = 3;
// int c = FUNC(++a, b); // ((a++) < (b) ? (a++) : (b)) a :3 b:3 c: 3
// cout << "a :" << a << " b:" << b << " c: " << c << endl;


int c = FUNC2(++a, b); //((a++) < (b) ? (a) : (b)) a :2 b:3 c: 2
cout << "a :" << a << " b:" << b << " c: " << c << endl;

return 0;

构造方法与析构方法

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
class myClass {
int _age;
public:
myClass() {
std::cout << "无参构造";
}
myClass(int age) {
_age = age;
}
myClass(const myClass &obj) {
_age = obj._age;
}

~myClass() {
std::cout << "我是析构方法" << std::endl;
}
void myClass::setAge(int age){
_age = age;
}
int getAge() {
return _age;
}
};
int main(int argc, const char * argv[]) {
myClass c(18);
myClass d = c;
myClass e;
cout << "age: " << c.getAge() <<endl;
cout << "age: " << d.getAge() <<endl;
return 0;
}

当一个类含有变量是类并有有参构造方法

必须要初始化参数类的构造方法

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
class c1 {
public:
c1(int a) {
cout << "c1 构造方法 " << endl;
}
~c1() {
cout << "c1 析构方法" << endl;
}
};
class c2 {
public:
c1 a1;
c1 a2;
c2(int m1, int m2, int m3) : a1(m2), a2(m3)
{
cout << "c2 构造方法 " << endl;
}
~c2() {
cout << "c2 析构方法" << endl;
}
};

int main(int argc, const char * argv[]) {
c2 a2(1, 2, 3);
/**
c1 构造方法
c1 构造方法
c2 构造方法
c2 析构方法
c1 析构方法
c1 析构方法
**/
return 0;
}

构造方法里调构造方法问题

会直接初始化一个类, 然后直接析构掉

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
class c3 {
public:
int _a;
int _b;
int _c;
c3(int a, int b) {
cout << "2个参数构造方法" << endl;
c3(a, b, 100);
}
c3 (int a, int b, int c) {
cout << "3个参数构造方法" << endl;
_a = a;
_b = b;
_c = c;
}

void printParmas() {
cout << "_a: " << _a << " _b: " << _b << " _c: " << _c << endl;
}

~c3() {
cout << "析构方法被调用" << endl;
}
};
int main(int argc, const char * argv[]) {
c3 c(1, 2);
c.printParmas();
/***
2个参数构造方法
3个参数构造方法
析构方法被调用
_a: 0 _b: 0 _c: 0
析构方法被调用
**/
return 0;
}

类中的static变量

同一个类的所有对象公用同一个static变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class c4 {
public:
int a = 0;
static int b;
void coutParams() {
cout << "a: " << a << " b: " << b << endl;
}
void addParams() {
a ++;
b ++;
}
};
int c4::b = 0; //必须在外面声明
int main(int argc, const char * argv[]) {
c4 c1, c2;
c1.coutParams();
c2.coutParams();
c1.addParams();
c2.addParams();
c1.coutParams();
c2.coutParams();
return 0;
}

类中的static方法

static方法中只能使用static变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class c5 {
public:
int a = 0;
static int b;
//static方法中只能使用static变量
static void coutParams() {
cout << " b: " << b << endl;
}
void addParams() {
a ++;
b ++;
}
};
int c5::b = 0;
int main(int argc, const char * argv[]) {
c5 c1, c2;
c1.coutParams();
c1.addParams();
c5::coutParams();
c1.coutParams();
return 0;
}

类的大小

下面这个类对象只占4字节而不是16字节, 他们是怎么分配内存的呢? 其实c5是用结构体实现的, 只有a变量是放在结构体c1的内存里, 静态变量b和静态方法coutParams都放在全局内存区, addParams放在代码内存区;
那么问题来了, 那调用addParams时如何区别是哪个对象调用的呢? 其实cpp编译会将当前对象以一个变量名为this的变量传递给方法, 因此这也是为什么我们能再方法内使用this变量来调用对象的变量和方法

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
class c5 {
public:
int a = 0;
static int b;
static void coutParams() {
cout << " b: " << b << endl;
}
void addParams() {
a ++;
b ++;
}
};
int c5::b = 0;
int main(int argc, const char * argv[]) {
c5 c1;

cout << "c1 size: " << sizeof(c1) << endl; // 4
return 0;
}


// c5转换为c代码是如下
struct c5{
int a = 0;
}
//代码区
void addParams(const c5 this) {
a ++;
b ++;
}
//静态区
static int b;
static void coutParams() {
cout << " b: " << b << endl;
}

new和delete

new/delete与malloc/free 功能类似, 都是向堆区申请内存, 并且可以混用, 但是new会调用类的构造方法, delete会调用类的析构方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(int argc, const char * argv[]) {
int * p1 = new int(11);
char * p2 = new char[100];
strcpy(p2, "hello world");
c3* p3 = new c3(1, 2);
cout << "p1: " << *p1 << endl;

cout << "p2: " << p2 << endl;

delete p1;
delete []p2;
delete p3;
return 0;
}

类的const

void setA() const ==> void setA(const c1 * const this)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class c1 {
public:
int a;
void setA() const
{
// this->a = 100; 这里会报错 因为有const修饰
}
int getA() {
return this->a;
}
};

int main(int argc, const char * argv[]) {
c1 c;
c.setA();
cout<< " a: " << c.getA() << endl;
return 0;
}

方法返回类引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class C1 {
public:
int a;
C1(int a = 0) {
this->a = a;
}
C1& add(C1 c2) {
this->a = this->a + c2.a;

return *this;
}

void printA() {
cout << " a: " << this->a << endl;
}
};

int main(int argc, const char * argv[]) {
C1 c1(1), c2(2);
c1.add(c2);
c1.printA(); // a: 3
c2.printA(); // a: 2
return 0;
}

友元函数

通过friend申明为友元方法, 可以使用外部函数直接修改类的私有变量

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
class C1 {
private:
int a;
public:
friend void modifyA(C1 &c, int _a);
C1(int a = 0) {
this->a = a;
}
C1& add(C1 c2) {
this->a = this->a + c2.a;

return *this;
}

void printA() {
cout << " a: " << this->a << endl;
}
};

void modifyA(C1 &c, int _a) {
c.a = _a;
}

int main(int argc, const char * argv[]) {
C1 c1(1);
c1.printA();
modifyA(c1, 100);
c1.printA();
return 0;
}

友元类

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
class C1 {
private:
int a;
public:
friend class C2;
C1(int a = 0) {
this->a = a;
}
C1& add(C1 c2) {
this->a = this->a + c2.a;

return *this;
}

void printA() {
cout << " a: " << this->a << endl;
}
};

class C2 {
private:
C1 c;
public:
void setC1A(int _a) {
c.a = _a;
}
void printA() {
cout << " a: " << c.a << endl;
}
};

int main(int argc, const char * argv[]) {
C2 c2;
c2.printA();
c2.setC1A(100);
c2.printA();
return 0;
}

类的重载

重载必须发生在同一类中, 继承的同名方法只会覆盖重写, 不能发生重载

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
class Human {
public:
virtual void introduce() {
cout << " I am Human" << endl;
}
void echo(char* p, int a) {
cout << "echo: " << p << " a: " << a << endl;
}
virtual ~Human() {
cout << "Human 析构函数" << endl;
}
};

class Man : public Human {
public:
void introduce() {
cout << " I am Man " << endl;
}
void echo(char* p) {
cout << "echo: " << p << endl;
}
~Man() {
cout << "Man 析构函数" << endl;
}
};

class Woman : public Human {
public:
void introduce() {
cout << " I am Human " << endl;
}
~Woman() {
cout << "Woman 析构函数" << endl;
}
};

int main(int argc, const char * argv[]) {
Human *human = NULL;
Man man = Man();
Woman woman = Woman();
human = &man;

man.echo("hello");
man.Human::echo("hello", 1);//无法直接调用man.echo("hello", 1)

return 0;
}

类的操作符重载

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

class C3 {
int* arr;
int a = 0;
//因为是私有变量所以需要将全局函数声明为友元函数
friend C3 operator+(C3 &c1, C3 &c2);
friend C3 operator++(C3 &c1, int);
public:
C3(int a) {
this->a = a;
this->arr = new int[100];
}

void printA() {
cout << "a: " << this->a << endl;
}

//第一种 用类方法声明
C3 operator-(C3 &c2) {
C3 tmp(0);
tmp.a = this->a - c2.a;

return tmp;
}

//一元操作符重载
C3& operator++() {
this->a++;

return *this;
}

//后置--
C3 operator--(int) {
C3 tmp = *this;
this->a--;

return tmp;
}

int& operator[](int i) {
this->arr[i] = i;

return i;
}
};
//第二种 使用全局函数声明
C3 operator+(C3 &c1, C3 &c2) {
C3 tmp(0);
tmp.a = c1.a + c2.a;

return tmp;
}
C3 operator++(C3 &c1, int){
C3 tmp = c1;
c1.a ++;
return tmp;
}
int main(int argc, const char * argv[]) {
C3 c1(1), c2(2);

C3 c3 = c1 + c2;
c3.printA();
C3 c4 = c1 - c2;
c4.printA();
++c4;
c4.printA();
for (int i = 0; i < 5; i ++) {
c4[i] = i;
cout << c4[i] << endl;
}
return 0;
}

类继承

类继承也有三种修饰符public, protected, private

  • public继承, 就是默认继承
  • protected继承, public属性和方法都会变成protected
  • private继承, public, protected属性和方法都会变成private

    属性的重写

    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
    class Parent {
    public:
    int a;
    protected:
    int b;
    private:
    int c;
    public:
    void printAll() {
    cout << "a: " << a << " b:" << b << " c:" << c << endl;
    }
    };
    class Son : public Parent{
    public:
    int b;
    void printAll2() {
    cout << "a: " << a << " b:" << b << endl;
    }
    };

    int main(int argc, const char * argv[]) {
    Son s1;
    s1.a = 1;
    s1.b = 2;
    s1.Parent::a = 2;
    s1.printAll(); //a: 2 b:0 c:0
    s1.printAll2(); //a: 1 b:2

    return 0;
    }

继承的构造方法和析构方法执行顺序

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
55
56
57
58
59
60
61
62
63
64
65
class Object {
public:
int o1;
int o2;
Object(int o1, int o2) {
this->o1 = o1;
this->o2 = o2;
cout << "Object 构造方法: o1: " << o1 << " o2: " << o2 << endl;
}
~Object() {
cout << "Object 析构方法: o1: " << o1 << " o2: " << o2 << endl;
}
};
class Parent: public Object {
public:
int a;
protected:
int b;
private:
int c;
public:
Parent(int a, int b) : Object(a + 1, b + 1) {
this->a = a;
this->b = b;
cout << "Parent 构造方法: a: " << a << " b: " << b << endl;
}
~Parent() {
cout << "Parent 析构方法: a: " << a << " b: " << b << endl;
}
void printAll() {
cout << "a: " << a << " b:" << b << " c:" << c << endl;
}
};
class Son : public Parent{
public:
int b;
Object o1;
Object o2;
Son(int a, int b) : o2(a, 2), Parent(a+1, b + 1), o1(a, b) {
cout << "Son 构造方法: a: " << a << " b: " << b << endl;
}
~Son() {
cout << "Son 析构方法" << endl;
}
void printAll2() {
cout << "a: " << a << " b:" << b << endl;
}
};

int main(int argc, const char * argv[]) {
Son s1(1, 2);
/**
Object 构造方法: o1: 3 o2: 4
Parent 构造方法: a: 2 b: 3
Object 构造方法: o1: 1 o2: 2
Object 构造方法: o1: 1 o2: 2
Son 构造方法: a: 1 b: 2
Son 析构方法
Object 析构方法: o1: 1 o2: 2
Object 析构方法: o1: 1 o2: 2
Parent 析构方法: a: 2 b: 3
Object 析构方法: o1: 3 o2: 4
**/
return 0;
}

虚继承与继承二义性

如下, B1与B2都继承了A, C又同时继承了B1和B2, 这样就产生了二义性,
为了防止产生二义性应该给B1, B2添加virtual, 表示虚继承, 这样A的构造函数只会被执行一次,
虚继承会给类多加了8字节的数据;
如果在2个类中出现同样名称的变量, 只能通过 obj.class::var的方式来解决二义性

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
cclass A {
public:
int a;
A() {
cout << "I am A" << endl;
}
};

class B1 : virtual public A {
public:
int b;

};

class B2 : virtual public A {
public:
int b;
};

class C4: public B1, public B2 {
public:
int c;
};

int main(int argc, const char * argv[]) {
C4 c;
c.a = 1;
c.B1::b = 2;
c.B2::b = 3;
cout << "sizeof(A): " << sizeof(A) << endl;
cout << "sizeof(B1): " << sizeof(B1) << endl;
cout << "sizeof(B2): " << sizeof(B2) << endl;
cout << "sizeof(C4): " << sizeof(C4) << endl;
/**
I am A
sizeof(A): 4
sizeof(B1): 16
sizeof(B2): 16
sizeof(C4): 40
/*
return 0;
}

多态

想让方法实现多态, 必须给方法添加上virtual, 否则使用多态调用时, 只会调用父类的方法, 而不是自己的方法;
没加virtual, 是静态联编, 就是说调用哪个方法, 在编译阶段已经确定;
加了virtual, 是动态联编, 就是说调用哪个方法, 只调用的时候的确定

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
class Human {
public:
virtual void introduce() {
cout << " I am Human" << endl;
}
};

class Man : public Human {
public:
void introduce() {
cout << " I am Man " << endl;
}
};

class Woman : public Human {
public:
void introduce() {
cout << " I am Human " << endl;
}
};

void introduce(Human *p) {
p->introduce();
}
int main(int argc, const char * argv[]) {
Human *human = NULL;
Man man = Man();
Woman woman = Woman();
human = &man;

introduce(&man);
introduce(&woman);
introduce(human);
return 0;
}

用函数指针实现多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//第一种
typedef void (*myFunc)(int a, int b);
//void likeMultiPoly(myFunc p, int a, int b) {
// 第二种
void likeMultiPoly(void (*p)(int a, int b) , int a, int b) {
p(a, b);
}
void func2(int a, int b) {
printf("func2 a: %d, b: %d\n", a, b);
}
void func3(int a, int b) {
printf("func3 a: %d, b: %d\n", a, b);
}

void func4(int a, int b) {
printf("func4 a: %d, b: %d\n", a, b);
}
int main(int argc, const char * argv[]) {

likeMultiPoly(func2, 1, 2);
likeMultiPoly(func3, 3, 4);
likeMultiPoly(func4, 5, 6);
return 0;
}

虚析构函数

如果通过多态的方式, 释放对象内存, 必须给析构函数加上vitrual, 否则只会调用父类的析构函数, 子类的析构函数不会被调用, 而导致内存溢出

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
class Human {
public:
virtual void introduce() {
cout << " I am Human" << endl;
}
virtual ~Human() {
cout << "Human 析构函数" << endl;
}
};

class Man : public Human {
public:
void introduce() {
cout << " I am Man " << endl;
}
~Man() {
cout << "Man 析构函数" << endl;
}
};

class Woman : public Human {
public:
void introduce() {
cout << " I am Human " << endl;
}
~Woman() {
cout << "Woman 析构函数" << endl;
}
};

void introduce(Human *p) {
p->introduce();
}
void deleteHuman(Human *p) {
delete p;
}
int main(int argc, const char * argv[]) {
Human *human = NULL;
Man man = Man();
Woman woman = Woman();
human = &man;

introduce(&man);
introduce(&woman);
introduce(human);

Human *man2 = new Man();
deleteHuman(man2);
cout << "==========" << endl;
return 0;
}

vptr 指针

cpp的多态是使用vptr指针实现的, 即每个类都会生成一份虚函数映射表, 然后把虚函数放入, 然后通过vptr指针获取对应的虚函数

子类的vptr指针是分步初始化的

子类的vptr指针是在构造函数执行完毕后才初始化完成的

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
class Parent {
public:
Parent() {
print();
}
virtual void print() {
cout << "I am Parent" << endl;
}
};

class Son : public Parent {
public:
Son() {
print();
}
virtual void print() {
cout << "I am Son" << endl;
}
};
int main(int argc, const char * argv[]) {
Son s1;
/**
* I am Parent
* I am Son
*/
return 0;
}

纯虚函数 -> 抽象函数

cpp中的接口是用纯虚函数+多继承实现的

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
55
56
57
58
59
60
61
62
class interface1 {
public:
virtual void run() = 0;
virtual void eat() = 0;
};
class interface2 {
public:
virtual void run() = 0;
virtual void echo() = 0;
};

class Human : public interface1, public interface2 {
public:
void run() {
cout << "I am running" << endl;
}
void echo() {
cout << "hello world" << endl;
}
void eat() {
cout << "I like delicious foods" << endl;
}
};
class Pig : public interface1 {
public:
void run() {
cout << "I am running" << endl;
}
void echo() {
cout << "gu gu gu" << endl;
}
void eat() {
cout << "I like any food" << endl;
}
};
class Dog : public interface2 {
public:
void run() {
cout << "I am running" << endl;
}
void echo() {
cout << "Wang Wang Wang" << endl;
}
};
void doSomething(interface1* inter) {
inter->run();
inter->eat();
}
void doSomething2(interface2* inter) {
inter->run();
inter->echo();
}
int main(int argc, const char * argv[]) {
Human h1;
Pig p1;
Dog d1;
doSomething(&h1);
doSomething(&p1);
doSomething2(&h1);
doSomething2(&d1);
return 0;
}