C++面向对象 Focused Reading 0 Categories / 0 Tags / 5.9k Words
Cpp Note

C++面向对象

C++面向对象编程知识点总结

2026.04.17 Updated 2026.05.07 5.9k Words

C++

面向对象编程

面向对象编程的三大特性分别为:封装、继承、多态.

属性和行为

封装主要指对属性和行为的封装.

封装的语法:

1
2
3
4
5
class 类名{
访问权限: // 一共有三种 public、private、protected
属性(成员变量)
行为(成员函数)
};

其中访问权限一共有三类:public、private、protected.

举个例子:

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
#include <iostream>
using namespace std;

class Hero
{
public:
int m_Id;
int m_Hp;

void addHp(int hp)
{
m_Hp += hp;
}
void subHp(int hp)
{
m_Hp -= hp;
}
};

int main()
{
// 通过类来生成对象的过程,叫做实例化
Hero h;
// 访问对象属性
h.m_Id = 0;
h.m_Hp = 100;
h.addHp(100);
cout << "HP:" << h.m_Hp << endl;
h.subHp(100);
cout << "HP:" << h.m_Hp << endl;

system("pause");
return 0;
}

通过类来生成对象的过程,叫做实例化.

访问权限

访问权限一共有三种:

  • 公共权限 public 类内可以访问,类外也可以访问
  • 保护权限 protected 类内可以访问,类外不可以访问 子类可以访问
  • 私有权限 private 类内可以访问,类外不可以访问 子类不可以访问

B —> A B继承于A类,则 A为父类、基类。B类为子类、派生类. 其中子类B是可以访问A类的保护成员,无法访问A类中私 有权限的成员.

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
#include <iostream>
using namespace std;

class People
{
public:
int m_Id;

protected:
int m_HouseId;

private:
int m_Paypass;

public:
void work()
{
// 所有成员变量,类内均可以放访问
m_Id = 1;
m_HouseId = 2;
m_Paypass = 1314;
}
};

class son : public People //继承
{
void work1()
{
m_Id = 1;
// 保护子类可以访问
m_HouseId = 2;
// 私有子类无法访问
m_Paypass = 1314; // 编译器报错 member "People::m_Paypass" (declared at line 13) is inaccessible
}
};

int main()
{
People p;
p.m_Id = 1;
// 保护 和 私有 类外无法访问
p.m_HouseId = 3; // 编译器报错 member "People::m_HouseId" (declared at line 1e) is inaccessible
p.m_Paypass = 333; //编译器报错 member "People::m_HouseId" (declared at line 1e) is inaccessible

return 0;
}

class和struct

struct 的权限默认是公共的class 的权限默认是私有的.

c++中的struct是可以定义成员函数的,而c 里的struct是无法定义成员函数的. 这是cc++ 中struct的区别.

所以c++中 class和struct的区别只有访问权限的区别.

属性私有化

属性变成私有以后,可以通过一些函数、方法、接口的方式来控制它的读写权限.

  • 可以控制读写权限
  • 可以检测数据的有效性
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
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
void SetName(string name)
{
m_Name = name;
}
string GetName()
{
return m_Name;
}
string GetGender()
{
return m_gender;
}
void SetRank(int rank)
{
// 检测数据有效性
if (rank <= 0 || rank > 50)
{
cout << "rank is not legal" << endl;
return;
}
m_rank = rank;
}

private:
string m_Name; // 可读可写
string m_gender = "male"; // 只读
int m_rank; // 只写
};

int main()
{
Student s;
s.SetName("dong");
cout << s.GetName() << endl;
cout << s.GetGender() << endl;
s.SetRank(1);
system("pause");

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
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
// 默认构造函数
Student()
{
m_Name = "";
m_gender = "male";
m_rank = 1;
cout << "default constructor function" << endl;
}
// 有参构造函数
Student(string name)
{
m_Name = name;
m_gender = "male";
m_rank = 1;
cout << "parameterized constructor function" << endl;
}

private:
string m_Name;
string m_gender;
int m_rank;
};

int main()
{
Student s1;
Student s2("dong");
Student s3(); // 这是一个函数声明 好比 int main() 不会调用任何构造函数
Student s4{}; // 无参的话 如s1 或者 s4这样
Student s5 = Student("dong"); // Student("dong")生成一个匿名对象赋值给s5 这也是一个有参构造写法

system("pause");

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
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
// 默认构造函数
Student()
{
cout << "default constructor function" << endl;
}
~Student()
{
cout << "destructor function" << endl;
}
};

int main()
{
{
Student s1; // s1 属于这个小括号作用域
} // 这里离开作用域,马上析构

system("pause"); // 此时析构信息已经打印完了
return 0;
}

拷贝构造函数

拷贝构造函数目的使用一个对象构造出另一个对象.

拷贝构造函数定义:

1
类名(const 类型&变量名) 

引用确保传参时不会多一次拷贝,const确保传进来的参数不会被改变

拷贝构造函数调用时机:

  • 用已经创建的对象来初始化对象、
  • 函数的传参
  • 函数的返回值
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
74
75
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
// 默认构造函数
Student()
{
cout << "default constructor function" << endl;
}
// 有参构造函数
Student(string name)
{
m_Name = name;
cout << "parameterized constructor function" << endl;
}
// 拷贝构造函数
Student(const Student &student)
{
m_Name = student.m_Name;
cout << "copy constructor function" << endl;
}
~Student()
{
cout << "destructor function" << endl;
}

private:
string m_Name;
};
// 1.用已经创建的对象来初始化对象

void func1()
{
cout << "---------------func1----------------" << endl;
Student s1("dong");
Student s2(s1);
}
// 2.函数的传参
void test1(Student s)
{
}
void test2(Student *s)
{
}
void func2()
{
cout << "---------------func2----------------" << endl;
Student s3;
test1(s3);
test2(&s3); // 传入指针不会调用构造copy构造函数,因为没有生成新的对象
}
// 3.函数的返回值
Student test3()
{
Student s4("liu");
return s4;
}
void func3()
{
cout << "---------------func3----------------" << endl;
Student s = test3();
}
int main()
{
func1();
func2();
func3();

system("pause");

return 0;
}

初始化列表

初始化列表是对对象初始化用的,语法如下:

1
构造函数():成员变量1(传参1),成员变量2(传参2){}
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
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
// 有参构造函数
// Student(string name, int score)
// {
// m_Name = name;
// m_score = score;
// }
// 初始化列表语法
Student(string name, int score) : m_Name(name), m_score(score)
{
}
void Print()
{
cout << m_Name << " " << m_score << endl;
}

private:
string m_Name;
int m_score;
};

int main()
{
Student s1("dong", 100);
s1.Print();

system("pause");

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
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
Student()
{
m_Name = "dong";
m_Score = 100;
}
~Student()
{
}
// 静态成员变量定义
static int m_StudentCount;

private:
string m_Name;
int m_Score;
};

int Student::m_StudentCount = 50;

int main()
{
Student s1;
cout << s1.m_StudentCount << endl; //50
s1.m_StudentCount = 101;
cout << Student::m_StudentCount << endl; //101

cout << &(s1.m_StudentCount) << endl; //打印出来地址一样
cout << &(Student::m_StudentCount) << 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
35
36
37
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
Student()
{
m_Name = "dong";
m_Score = 100;
}
~Student()
{
}
// 静态成员变量定义
static int m_StudentCount;
static int GetStudentCount()
{
return m_StudentCount;
}

private:
string m_Name;
int m_Score;
};

int Student::m_StudentCount = 50;

int main()
{
Student s1;
cout << s1.GetStudentCount() << endl; //50
cout << Student::GetStudentCount() << endl; //50

return 0;
}

this指针

类里有个变量叫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
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
Student(int score)
{
// this代表指向对象本本身
// this = &h *this = *(&h) == h
this->score = score;
cout << this << endl;
}
int score;
};

int main()
{
Student s1(100);
cout << s1.score << endl;
cout << &s1 << endl; // 跟this打印出来的地址一样,说明this代表这个对象的地址

return 0;
}

const修饰成员函数

成员函数的参数和函数体之间加上一个const叫做常函数. 常函数的函数体中不能修改成员属性的值.

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
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
Student() : score(100) {}
int GetScore() const
{
// 加入Const后杜绝修改 成员变量值
// score += 1;
return score;
}
int SetScore(int score)
{
this->score = score;
}

private:
int score;
};

int main()
{
const Student s1;
s1.SetScore(100); // 无法调用 会报错
return 0;
}

mutable关键字

为了让成员变量可以在常函数里修改,需要加入一个关键字即mutable.

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
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
Student() : score(100), counter(0) {}
int GetScore() const
{
counter++;
return score;
}
void printCounter() const
{
cout << "Counter:" << counter << endl;
}

private:
int score;
mutable int counter;
};

int main()
{
const Student s1;
s1.GetScore(), s1.GetScore(), s1.GetScore();
s1.printCounter(); // 3
}

友元

友元的目的是让一个函数或者一个类能够访问另外一个类的私有成员.

友元的关键字: 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
31
32
#include <iostream>
#include <string>
using namespace std;

class Student
{
// 加上friend声明这个函数就可以访问私有成员了
friend void test1(Student *s);

public:
Student() : score(100), name("dong") {}

public:
string name;

private:
int score;
};

void test1(Student *s)
{
cout << s->name << endl;
cout << s->score << endl;
}

int main()
{
Student s1;
test1(&s1);

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
#include <iostream>
#include <string>
using namespace std;

class Student
{
// 加上friend声明之后Teacher类就可以访问Student类私有成员
friend class Teacher;

public:
Student() : score(100), name("dong") {}

public:
string name;

private:
int score;
};

class Teacher
{
public:
Teacher() {}
void visit(Student *s)
{
cout << s->score << endl;
}
};

int main()
{
Student s1;
Teacher t1;
t1.visit(&s1);

return 0;
}

成员函数作为友元

上面例子中是通过友元将Teacher类访问Student类的私有成员变量.

现在目的是 将Teacher类的成员函数能够访问Student类的私有成员变量. 即成员函数作为友元.

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
#include <iostream>
#include <string>
using namespace std;

class Student;

class Teacher
{
public:
Teacher() {}
void visit(Student *s);
};

class Student
{
// 加上friend声明之后Teacher类就可以访问Student类私有成员
friend void Teacher::visit(Student *s);

public:
Student() : score(100), name("dong") {}

public:
string name;

private:
int score;
};

void Teacher::visit(Student *s)
{
cout << s->score << endl;
}
int main()
{
Student s1;
Teacher t1;
t1.visit(&s1);

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
#include <iostream>
#include <string>
using namespace std;

class Complex
{
public:
Complex() : real(0), image(0)
{
}
Complex(int real, int image)
{
this->real = real;
this->image = image;
}
// Complex add(Complex &other)
// {
// Complex ret;
// ret.real = this->real + other.real;
// ret.image = this->image + other.image;
// return ret;
// }
Complex operator+(Complex &other) // 加法运算符重载
{
Complex ret;
ret.real = this->real + other.real;
ret.image = this->image + other.image;
return ret;
}
void Print()
{
cout << real << "+" << image << "i" << endl;
}

private:
int real;
int image;
};

int main()
{
Complex a(1, 2);
Complex b(2, 3);
// Complex c = a.add(b);
Complex c = a + b;
c.Print();

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
#include <iostream>
#include <string>
using namespace std;

class Complex
{
friend Complex operator+(Complex &a, Complex &b); // 全局函数重载需要引入友元

public:
Complex() : real(0), image(0)
{
}
Complex(int real, int image)
{
this->real = real;
this->image = image;
}

void Print()
{
cout << real << "+" << image << "i" << endl;
}

private:
int real;
int image;
};

Complex operator+(Complex &a, Complex &b) // 全局函数方式加法运算符重载
{
Complex ret;
ret.real = a.real + b.real;
ret.image = a.image + b.image;
return ret;
}

int main()
{
Complex a(1, 2);
Complex b(2, 3);
// Complex c = a.add(b);
Complex c = a + b;
c.Print();

return 0;
}

左移重载

左移的目的是把这个对象输出出来.Complex c;cout.operator<<(c)

但是成员函数重载应该是c在前面c.operator<<(cout) ,这才是成员函数的重载.

正常情况下是cout<<c, 但此时相当于是cout.operator<<©,即operator <<相当于cout的成员函数,会输出不出来定义的Complex c,因此需要<< 变为Complex类的成员函数,此时这种情况下实现就变成了c.operator<<(cout),仍然不是想要的cout<<c,因此需要从成员函数抽出来变成一个全局函数,然后全局函数作为友元声明,同时为了能够链式输出加上返回值类型ostream&.

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 <string>
using namespace std;

class Complex
{
friend Complex operator+(Complex &a, Complex &b);
friend ostream &operator<<(ostream &cout, Complex a);

public:
Complex() : real(0), image(0)
{
}
Complex(int real, int image)
{
this->real = real;
this->image = image;
}

void Print()
{
cout << real << "+" << image << "i" << endl;
}

private:
int real;
int image;
};

Complex operator+(Complex &a, Complex &b)
{
Complex ret;
ret.real = a.real + b.real;
ret.image = a.image + b.image;
return ret;
}

ostream &operator<<(ostream &cout, Complex a) // 左移运算符重载
{
cout << a.real << "+" << a.image << 'i';
return cout;
}

int main()
{
Complex a(1, 2);
Complex b(2, 3);
// Complex c = a.add(b);
Complex c = a + b;
c.Print();
cout << 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <string>
using namespace std;

class Complex
{
friend ostream &operator<<(ostream &cout, Complex a);

public:
Complex() : real(0), image(0)
{
}
Complex(int real, int image)
{
this->real = real;
this->image = image;
}

// 前置++
Complex &operator++()
{
this->real += 1;
return *this;
}
// 后置++
Complex operator++(int)
{
Complex c = *this;
this->real += 1;
return c;
}

private:
int real;
int image;
};

ostream &operator<<(ostream &cout, Complex a)
{
cout << a.real << "+" << a.image << "i";
return cout;
}

int main()
{
Complex a(10, 10);
cout << a << endl;
cout << a++ << endl;
cout << a << endl;
// cout << ++(++a) << 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
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using namespace std;

class Student
{
public:
Student() : m_data(NULL) {}
Student(int data)
{
m_data = new int;
*m_data = data;
}
~Student()
{
if (m_data)
{
delete m_data;
m_data = NULL;
}
}

Student &operator=(Student &h)
{
if (m_data)
{
delete m_data;
m_data = NULL;
}
m_data = new int;
*m_data = *h.m_data;
return *this;
}

int *m_data;
};
int main()
{
Student s1(1);
Student s2(2);
cout << s1.m_data << endl;
cout << s2.m_data << endl;
s1 = s2; // 内存泄漏
cout << s1.m_data << endl;
cout << s2.m_data << endl;
return 0;
}

继承

继承的语法:

1
class 子类:继承方式 父类{}

子类又叫做派生类,父类叫做基类. 当我们写了几个类,然后发现它们有些共性,把这些共性抽取出来实现一个新的类,这个新的类就叫做基类或者父类.然后将之前的类都来继承它,那两个类就成为子类或派生类.

继承方式

继承方式一共有三种:

  • public
  • protected
  • private

同时访问权限也一共有3种,组合一下是3*3=9种. 也就是原本在父类里面的访问权限通过继承方式作用后到子类里面,访问权限就会改变,总共有9种权限了.

子类继承方式\父类访问权限 public protected private
public public**** protected 无法访问
protected protected protected 无法访问
private private private 无法访问

中间的3*3代笔子类的访问权限.

构造和析构顺序

继承中,构造链里,先构造的后析构.

d->b->c->a ,那么构造析构顺序:a b c d d c b a

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
#include <iostream>
using namespace std;

class Animal
{
public:
Animal()
{
cout << "Animal Constructor" << endl;
}
~Animal()
{
cout << "Animal Deconstructor" << endl;
}
};
class Cat : public Animal
{
public:
Cat()
{
cout << "Cat Constructor" << endl;
}
~Cat()
{
cout << "Cat Deconstructor" << endl;
}
};
class BosCat : public Cat
{
public:
BosCat()
{
cout << "BosCat Constructor" << endl;
}
~BosCat()
{
cout << "BosCat Deconstructor" << endl;
}
};

void test()
{
Animal a;
// Cat b;
// BosCat c;
}

int main()
{
test();
return 0;
}

输出:

1.test()中只有 a

Animal Constructor
Animal Deconstructor

2.test()中只有 b

Animal Constructor
Cat Constructor
Cat Deconstructor
Animal Deconstructor

3.test()中只有 c

Animal Constructor
Cat Constructor
BosCat Constructor
BosCat Deconstructor
Cat Deconstructor
Animal Deconstructor

同名属性访问

同名属性指父类和子类都一个名字相同的变量. 当子类继承父类并且有一个同名变量名的时候,并不会进行覆盖,需要用一个作用域访问即可.

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
#include <iostream>
using namespace std;

class Animal
{
public:
Animal()
{
m_data = 1;
}
int m_data;
};
class Cat : public Animal
{
public:
Cat()
{
m_data = 2;
}
int m_data;
};

void test()
{
Cat c;
cout << c.m_data << endl; // 2
cout << c.Animal::m_data << endl; // 1
}

int main()
{
test();
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
#include <iostream>
using namespace std;

class Animal
{
public:
Animal()
{
}
void eat()
{
cout << "animal eat" << endl;
}
};
class Cat : public Animal
{
public:
Cat()
{
}
void eat()
{
cout << "cat eat" << endl;
}
};

void test()
{
Cat c;
c.eat();
c.Animal::eat();
}

int main()
{
test();
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
#include <iostream>
using namespace std;

class BaseA
{
public:
int m_A;
int m_Base;
BaseA() : m_A(0), m_Base(1) {}
};
class BaseB
{
public:
int m_B;
int m_Base;
BaseB() : m_B(0), m_Base(2) {}
};
class BaseC
{
public:
int m_C;
BaseC() : m_C(0) {}
};

class Son : public BaseA, public BaseB, public BaseC
{
};

int main()
{
Son s;
s.m_A = 1;
s.m_B = 2;
s.m_C = 3;
// s.m_Base=3; 会报错
s.BaseA::m_Base = 1;
s.BaseB::m_Base = 3;

cout << sizeof(s) << endl; // 20个字节 3个父类一共5个整形 4*5=20B
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
#include <iostream>
using namespace std;

class Animal
{
public:
void eat()
{
cout << "Animal eat" << endl;
}
};
class Cat : public Animal
{
public:
void eat()
{
cout << "Cat eat" << endl;
}
};
void eat(Animal &a)
{
a.eat();
}
void test()
{
Cat c;
eat(c);
}
int main()
{
test();
return 0;
}

打印结果:

“Animal eat”

如何调用到子类的函数?这时候引入虚函数的概念. 在父类函数前面加上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
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;

class Animal
{
public:
virtual void eat() // 虚函数
{
cout << "Animal eat" << endl;
}
};
class Cat : public Animal
{
public:
void eat()
{
cout << "Cat eat" << endl;
}
};
class Pig : public Animal
{
public:
void eat()
{
cout << "Pig eat" << endl;
}
};
void eat(Animal &a) //子类转换为父类对象,此时父类函数是个虚函数,实现了多态
{
a.eat();
}
void test()
{
Cat c;
Pig p;
eat(c);
eat(p);
}
int main()
{
test();
return 0;
}

打印结果:

Cat eat
Pig eat

多态表现在我的函数传参是个动物,但是传入不同的动物它能产生不同的行为.这个就叫做多态,如上面的例子.

纯虚函数和抽象类

有时候写代码会出现父类里面的函数没有任何实现,都需要子类去实现,也就是让子类去重写。纯虚函数的目的就是这个目的

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
#include <iostream>
using namespace std;

class Animal
{
// 只要有纯虚函数的类就叫做抽象类,抽象类是无法实例化对象的.
public:
virtual void eat() = 0; // 加上=0后 变成了一个纯虚函数
};

class Cat : public Animal
{
public:
virtual void eat() //子类必须重写这个纯虚函数,否则也是一个抽象类,无法实例化对象
{
cout << "cat eat" << endl;
}
};

int main()
{
Cat a;
a.eat();
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
#include <iostream>
using namespace std;

class BaseA
{
public:
BaseA() {}
~BaseA()
{
cout << "BaseA 销毁了" << endl;
}
};

class SonA : public BaseA
{
public:
SonA() : m_Value(NULL)
{
m_Value = new int(10);
}
~SonA()
{
cout << "SonA 销毁了" << endl;
delete m_Value;
}
int *m_Value;
};

class BaseB
{
public:
BaseB() {}
/*virtual ~BaseB() {
cout << "BaseB 销毁了" << endl;
}*/
virtual ~BaseB() = 0;
};

BaseB::~BaseB()
{
cout << "BaseB 销毁了" << endl;
}

class SonB : public BaseB
{
public:
SonB() : m_Value(NULL)
{
m_Value = new int(10);
}
~SonB()
{
cout << "SonB 销毁了" << endl;
delete m_Value;
}
int *m_Value;
};

int main()
{
BaseA *a = new SonA();
delete a;

BaseB *b = new SonB();
delete b;

// BaseB x; 抽象类无法进行实例化

return 0;
}