0%

C++ - 继承

最近在学习 C++,所以顺便将每日所学记录下来,一方面为了巩固学习的知识,另一方面也为同样在学习C++的童鞋们提供一份参考。

继承和多态是面向对象语言最强大的功能。有了继承和多态,我们可以完成代码重用。在C中有许多技巧可以实现多态。本文的目的就是演示一种简单和容易的技术,在C中应用继承和多态。通过创建一个VTable(virtual table)和在基类和派生类对象之间提供正确的访问,我们能在C中实现继承和多态。VTable能通过维护一张函数表指针表来实现。为了提供基类和派生类对象之间的访问,我们可以在基类中维护派生类的引用和在派生类中维护基类的引用。

继承

类关系

访问控制

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
#include <iostream>
using namespace std;
//类成员访问控制
//用private修饰的成员变量,在类内部可以使用
//用public修饰的成员变量,在类的内部和外部均可以使用
//用protected修饰的成员变量,在类的内部可以使用,在类的外部不可以被使用
class Test
{
public: //
int c;
protected: //
int b;
private: //
int a;
};

class Parent
{
public:
Parent(int a = 1, int b = 2, int c = 3)
{
this->a = a;
this->c = c;
this->b = b;
}
void PrintSelf()
{
cout << "Hello" << endl;
}
int c;
protected:
int b;
private: //
int a;
};

//子类从父类公有继承
class Child : public Parent
{
public:

void Print()
{
cout << a << endl; //不可以使用父类私有成员
cout << c << endl;
cout << b << endl;
}
protected:
private:
};


int main()
{
Child c1;
c1.c = 10;
c1.Print();
c1.PrintSelf();
system("pause");
return 0;
}

继承方式

Demo:

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
76
77
78
79
80
81
82
83
84
85
#include <iostream>
using namespace std;
//类的继承方式对子类对外访问属性影响
#include <cstdlib>

class A
{
private:
int a;
protected:
int b;
public:
int c;

A()
{
a = 0; b = 0; c = 0;
}

void set(int a, int b, int c)
{
this->a = a; this->b = b; this->c = c;
}
};

class B : public A
{
public:
void print()
{
//cout << "a = " << a; //私有成员不可访问
cout << "b = " << b;
cout << "c = " << endl;
}
};

class C : protected A
{
public:
void print()
{
//cout << "a = " << a; //私有不可访问
cout << "b = " << b;
cout << "c = " << endl;
}
};

class D : private A
{
public:
void print()
{
//cout << "a = " << a; //私有不可访问
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
};

int main()
{

A aa;
B bb;
C cc;
D dd;

aa.c = 100;
bb.c = 100;
//cc.c = 100; //类内可访问,类外不可以
//dd.c = 100; //

aa.set(1, 2, 3);
bb.set(10, 20, 30);
//cc.set(40, 50, 60); //类内可访问,类外不可以
//dd.set(70, 80, 90); //

bb.print();
cc.print();
dd.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
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <iostream>
using namespace std;

class Parent
{
public:
Parent();
~Parent();
void Print();
private:
protected:
int a;
int b;
};

Parent::Parent()
{
}

Parent::~Parent()
{
}

void Parent::Print()
{
cout << "父类" << endl;
}

class Child : public Parent
{
public:
Child();
~Child();
void Print();
private:
int c;
};

Child::Child()
{
a = 0;
b = 0;
c = 0;
}

Child::~Child()
{
}


void Child::Print()
{
cout << "子类" << endl;
}


void howToPoint(Parent *base)
{
base->Print();
}

void howToPoint_Test01(Parent &base)
{
base.Print();
}



void howToPoint_Test(Child *base)
{
base->Print();
}

void howToPoint_Test02(Child &base)
{
base.Print();
}



void main()
{
Child c1;
Parent p1;
c1.Print();
p1.Print();
Parent *base = NULL;
base = &c1;
base->Print();



Parent &base1 = c1;
base1.Print();


howToPoint(&c1);
howToPoint(&p1);


howToPoint_Test01(c1);
howToPoint_Test01(p1);


howToPoint_Test(&c1);
howToPoint_Test((Child *)&p1);


howToPoint_Test02(c1);
howToPoint_Test02((Child &)p1);


Parent p3 = c1; //子类对象初始化父类对象
system("pause");
}
  • 子类对象可以当作父类对象使用
  • 子类对象可以直接赋值给父类对象
  • 子类对象可以直接初始化父类对象
  • 父类指针可以直接指向子类对象
  • 父类引用可以直接引用子类对象

继承中的对象模型

  • 在子类对象构造的时候,需要调用父类构造函数对其继承得来的成员进行初始化
  • 在子类对象析构的时候,需要调用父类析构函数对其继承的来的成员进行清理
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
#include <iostream>
using namespace std;

class Parent
{
public:
Parent()
{
cout << "父类构造函数" << endl;
}
void PrintP()
{
printf("我是父类\n");
}


protected:
int a, b;
private:

};


class Child : public Parent
{
public:
Child()
{
a = 0; b = 0; c = 0;
cout << "子类构造函数" << endl;
}
void PrintC()
{
printf("我是子类\n");
}
protected:
private:
int c;
};


void howToPrint(Parent *p) //父类的指针
{
p->PrintP();
}

void howToPrint1(Parent &p)
{
p.PrintP();
}


int main()
{
Parent p1;
Child c1;
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
43
44
45
46
47
48
49
50
51
52
#include <iostream>
using namespace std;

class Parent
{
public:
Parent(char *p)
{
cout << "父类构造函数" << endl;
}
void PrintP()
{
printf("我是父类\n");
}


protected:
int a, b;
private:

};


class Child : public Parent
{
public:
Child() :Parent("sYstemk1t") //初始化列表
{
a = 0; b = 0; c = 0;
cout << "子类构造函数" << endl;
}
void PrintC()
{
printf("我是子类\n");
}
protected:
private:
int c;
};




int main()
{
Parent p1("sYstemk1t");
//Child c1;
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
#include <iostream>
using namespace std;

class A
{
public:
int a, b;
void Print()
{
cout << "我是父类" << endl;
cout << a << endl;
}
protected:
private:
};

class B : public A
{
public:
int a, b;
protected:
private:

};




void main()
{
B b1;
b1.a = 10;
b1.b = 20; //访问子类

b1.A::a = 20; //访问父类,加双冒号作用赋符号
b1.A::Print();
system("pause");
}

同名函数

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

class A
{

public:
int a, b;
void PrintA()
{
cout << "我是父类" << endl;
cout << a << endl;
}
void Print()
{
cout << "我是父类的A" << endl;
}
protected:
private:
};

class B : public A
{
public:
int a, b;

void Print()
{
cout << "我是子类的A" << endl;
}
protected:
private:

};




void main()
{
B b1;
b1.a = 10;
b1.b = 20; //访问子类

b1.A::a = 20; //
b1.A::PrintA();

b1.A::Print();
b1.Print();
system("pause");
}

派生类中的静态成员

  • 基类定义的静态成员,将被所有派生类共享
  • 根据静态成员自身的访问特性和派生类的集成方式,在类层次体系中具有不同的访问性质

静态成员

类中,静态成员变量被所有类的对象共享,(共享就是即使类的其中一个对象修改了该静态成员变量,那么类的其他所有对象再访问该静态成员变量时,就是修改后的值),所以可以认为该静态成员变量是属于该类的,而不属于某一个对象,且需要在类外被初始化,编译时就被创建并初始化;
静态成员函数只会被调用一次

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

class A
{
public:
A()
{
a = 10;
}
static int a;
int b;
void PrintA()
{
cout << "我是父类" << endl;
cout << a << endl;
}
void Print()
{
cout << "我是父类的A" << endl;
cout << a << endl;
}
protected:
private:
};

int A::a = 0; //告诉C++编译器需要给整个类分配4字节内存空间

class B : private A
{
public:
int b,c;

void Print()
{
cout << "我是子类的A" << endl;
cout << a << endl;
}
protected:
private:

};




void main()
{
//A a1;
B b1;
b1.Print();
system("pause");
}

多继承

一个类有多个直接基类的继承关系称为多继承

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

class Base1
{
public:
Base1() //先被调用
{
b1 = 1;
}
int b1;
protected:
private:

};


class Base2
{
public:
Base2() //后调用
{
b2 = 2;
}
int b2;

protected:
private:

};



class Child : public Base1,public Base2 //多继承
{
public:
Child()
{
;
}
void PrintB()
{
cout << b1 << endl;
cout << b2 << endl;
}
protected:

private:

};





int main()
{
Child c1;

c1.PrintB();
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
43
44
45
46
47
#include <iostream>
using namespace std;
class B
{
public:
int i;
private:
protected:
};


class B1 : virtual public B //虚继承
{
public:
int b1;
private:
protected:
};


class B2 : virtual public B
{
public:
int b2;
private:
protected:
};


class C : public B1,public B2
{
public:
private:
protected:
};



void main()
{
C c1;
c1.b1 = 10;
c1.b2 = 20;
c1.i = 30;
//c1.i = 30; //对i的访问不明确
system("pause");
}