Unreal Engine 游戏开发学习笔记 20181108


本篇博文实为在”系统”学习 Unreal Engine 4 游戏开发后整理的学习笔记。笔记按照每天的学习内容进行整理记录备忘。

本文为 Week3 Class4! 其中 表示上午的学习内容, 表示下午的学习内容。从本周开始连续三周学习 C++ 基础。同时强烈推荐像我一样的初学者看下”菜鸟教程”的 C++ 部分,本周的笔记绝大部分整理的内容均来自菜鸟笔记,只是内容按照上课老师所讲并在笔记中穿插了一些老师上课所讲实例,感谢菜鸟笔记网站管理员的无私分享。

今日内容摘要(知识点梳理):

1. 单例类
2. 多态继承(虚函数)
3. 函数重载
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 一般类构造函数都是公开的否则在函数外部不能实例化对象 类内部的成员没有排序的
// 单例类:只能被实例化一次
// 我们控制的一般只有一个玩家
// 私有化构造函数 在类的内部实例化一次
class PlayerCharacter {
private:
// 声明一个对象指针
static PlayerCharacter* Instance;
private:
// 声明一个私有的构造函数
PlayerCharacter() {}
static void Init() { Instance = new PlayerCharacter(); } //在堆内存中动态实例化一个对象
public:
static PlayerCharacter* GetPlayerCharacterInstance() {
if (Instance == 0) { Init(); } // 直接调用的话Instance是空,判断下如果是空指针就初始化Instance指针对象
return Instance;
}
};

PlayerCharacter* PlayerCharacter::Instance = nullptr;

// 上面的例子在没有对象生成的情况下访问不了 但是使用静态就可以直接通过类名访问了
// 静态函数直接通过类名访问
// 在没有实例化对象之前就可以调用函数,不能再静态函数中访问类的非静态成员 非静态函数中可以调用静态函数

class SkillManager {
private:
static SkillManager* Instance;
public:
static SkillManager* GetSkillManagerInstance() {
if (Instance == 0) {
Instance = new SkillManager();
}
return Instance;
}
};

SkillManager* SkillManager::Instance = nullptr;


int main
{
PlayerCharacter::GetPlayerCharacterInstance();
return 0;
}

多态继承

下面的实例中,基类 Shape 被派生为两个类,如下所示:

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

class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
int area()
{
cout << "Parent class area :" <<endl;
return 0;
}
};
class Rectangle: public Shape{
public:
Rectangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape{
public:
Triangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
// 程序的主函数
int main( )
{
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);

// 存储矩形的地址
shape = &rec;
// 调用矩形的求面积函数 area
shape->area();

// 存储三角形的地址
shape = &tri;
// 调用三角形的求面积函数 area
shape->area();

return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

1
2
Parent class area
Parent class area

导致错误输出的原因是,调用函数 area() 被编译器设置为基类中的版本,这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定,因为 area() 函数在程序编译期间就已经设置好了。
但现在,让我们对程序稍作修改,在 Shape 类中,area() 的声明前放置关键字 virtual,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
virtual int area()
{
cout << "Parent class area :" <<endl;
return 0;
}
};

修改后,当编译和执行前面的实例代码时,它会产生以下结果:

1
2
Rectangle class area
Triangle class area

此时,编译器看的是指针的内容,而不是它的类型。因此,由于 tri 和 rec 类的对象的地址存储在 * shape 中,所以会调用各自的 area() 函数。
正如您所看到的,每个子类都有一个函数 area() 的独立实现。这就是多态的一般使用方式。有了多态,您可以有多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。

虚函数

虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。

纯虚函数

您可能想要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。
我们可以把基类中的虚函数 area() 改写如下:

1
2
3
4
5
6
7
8
9
10
11
12
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
// pure virtual function
virtual int area() = 0;
};

= 0 告诉编译器,函数没有主体,上面的虚函数是纯虚函数。

C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数;形成多态必须具备三个条件:

  1. 必须存在继承关系;
  2. 继承关系必须有同名虚函数(其中虚函数是在基类中使用关键字Virtual声明的函数,在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数);
  3. 存在基类类型的指针或者引用,通过该指针或引用调用虚函数;

函数重载 运算符重载

C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。

C++ 中的函数重载

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。
下面的实例中,同名函数 print() 被用于输出不同的数据类型:

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 printData
{
public:
void print(int i) {
cout << "整数为: " << i << endl;
}

void print(double f) {
cout << "浮点数为: " << f << endl;
}

void print(char c[]) {
cout << "字符串为: " << c << endl;
}
};

int main(void)
{
printData pd;

// 输出整数
pd.print(5);
// 输出浮点数
pd.print(500.263);
// 输出字符串
char c[] = "Hello C++";
pd.print(c);

return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

1
2
3
整数为: 5
浮点数为: 500.263
字符串为: Hello C++

C++ 中的运算符重载

您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

1
Box operator+(const Box&);

声明加法运算符用于把两个 Box 对象相加,返回最终的 Box 对象。大多数的重载运算符可被定义为普通的非成员函数或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那么我们需要为每次操作传递两个参数,如下所示:

1
Box operator+(const Box&, const Box&);

下面的实例使用成员函数演示了运算符重载的概念。在这里,对象作为参数进行传递,对象的属性使用 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
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
#include <iostream>
using namespace std;

class Box
{
public:

double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}

void setBreadth( double bre )
{
breadth = bre;
}

void setHeight( double hei )
{
height = hei;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// 程序的主函数
int main( )
{
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
double volume = 0.0; // 把体积存储在该变量中

// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);

// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);

// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;

// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;

// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;

// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;

return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

1
2
3
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

可重载运算符/不可重载运算符

 可重载运算符列表(图片来自菜鸟教程)

下面是不可重载的运算符列表:
.:成员访问运算符
., ->:成员指针访问运算符
:::域运算符
sizeof:长度运算符
?::条件运算符

#: 预处理符号

运算符重载实例

值得注意的是:

  1. 运算重载符不可以改变语法结构。
  2. 运算重载符不可以改变操作数的个数。
  3. 运算重载符不可以改变优先级。
  4. 运算重载符不可以改变结合性。

类内的重载重载运算符(单参数)及友元函数重载运算符(多参数)

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
class Stone {

};

class Water {
private:
double Capacity = 0.0;
public:
friend Water WaterPlus(const Water& w, const Water& A);
friend class Stone;
public:
double GetCapacity() {
return Capacity;
}
public:
Water() {};
Water(double Cap) :Capacity(Cap) {};
public:
Water operator+(const Water& w) {
Water wa;
wa.Capacity = this->Capacity + w.Capacity;
return wa;
}

};

class Fluid {

};

// 类的多继承
class Sea :public Water, public Fluid {

};

// 需要运算符重载的时候只能通过友元函数写
// 友元函数可以直接访问私有属性
// 类也可以有友元类
Water WaterPlus(const Water& W, const Water& A)
{
Water NewW;
NewW.Capacity = W.Capacity + A.Capacity;
return NewW;
}

一元运算符重载

一元运算符只对一个操作数进行操作,下面是一元运算符的实例:

  • 递增运算符( ++ )和递减运算符( – )
  • 一元减运算符,即负号( - )
  • 逻辑非运算符( ! )
    一元运算符通常出现在它们所操作的对象的左边,比如 !obj、-obj 和 ++obj,但有时它们也可以作为后缀,比如 obj++ 或 obj–。
    下面的实例演示了如何重载一元减运算符( - )。
    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 Distance
    {
    private:
    int feet; // 0 到无穷
    int inches; // 0 到 12
    public:
    // 所需的构造函数
    Distance(){
    feet = 0;
    inches = 0;
    }
    Distance(int f, int i){
    feet = f;
    inches = i;
    }
    // 显示距离的方法
    void displayDistance()
    {
    cout << "F: " << feet << " I:" << inches <<endl;
    }
    // 重载负运算符( - )
    Distance operator- ()
    {
    feet = -feet;
    inches = -inches;
    return Distance(feet, inches);
    }
    };
    int main()
    {
    Distance D1(11, 10), D2(-5, 11);

    -D1; // 取相反数
    D1.displayDistance(); // 距离 D1

    -D2; // 取相反数
    D2.displayDistance(); // 距离 D2

    return 0;
    }

当上面的代码被编译和执行时,它会产生下列结果:

1
2
F: -11 I:-10
F: 5 I:-11

二元运算符重载

二元运算符需要两个参数,下面是二元运算符的实例。我们平常使用的加运算符( + )、减运算符( - )、乘运算符( * )和除运算符( / )都属于二元运算符。就像加(+)运算符。
下面的实例演示了如何重载加运算符( + )。类似地,您也可以尝试重载减运算符( - )和除运算符( / )。

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

class Box
{
double length; // 长度
double breadth; // 宽度
double height; // 高度
public:

double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}

void setBreadth( double bre )
{
breadth = bre;
}

void setHeight( double hei )
{
height = hei;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
};
// 程序的主函数
int main( )
{
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
double volume = 0.0; // 把体积存储在该变量中

// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);

// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);

// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;

// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;

// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;

// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;

return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

1
2
3
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

当 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<iostream>
using namespace std;
class A
{
private:
int a;
public:
A();
A(int n);
A operator+(const A & obj);
A operator+(const int b);
friend A operator+(const int b, A obj);
void display();
} ;
A::A()
{
a=0;
}
A::A(int n)//构造函数
{
a=n;
}
A A::operator +(const A& obj)//重载+号用于 对象相加
{
return this->a+obj.a;
}
A A::operator+(const int b)//重载+号用于 对象与数相加
{
return A(a+b);
}
A operator+(const int b, A obj)
{
return obj+b;//友元函数调用第二个重载+的成员函数 相当于 obj.operator+(b);
}
void A::display()
{
cout<<a<<endl;
}
int main ()
{
A a1(1);
A a2(2);
A a3,a4,a5;
a1.display();
a2.display();
int m=1;
a3=a1+a2;//可以交换顺序,相当月a3=a1.operator+(a2);
a3.display();
a4=a1+m;//因为加了个友元函数所以也可以交换顺序了。
a4.display();
a5=m+a1;
a5.display();
}

输出结果:

1
2
3
4
5
1
2
3
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
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
#include <iostream>
using namespace std;

class Box
{
double length; // 长度
double breadth; // 宽度
double height; // 高度
public:

double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}

void setBreadth( double bre )
{
breadth = bre;
}

void setHeight( double hei )
{
height = hei;
}

/**
* 改写部分 2018.09.05
* 重载 + 运算符,用于把两个 Box 对象相加
* 因为其是全局函数,对应的参数个数为2。
* 当重载的运算符函数是全局函数时,需要在类中将该函数声明为友员。
*/
friend Box operator+(const Box& a, const Box& b);

};

Box operator+(const Box& a, const Box& b)
{
Box box;
box.length = a.length + b.length;
box.breadth = a.breadth + b.breadth;
box.height = a.height + b.height;
// cout << box.length << "--" << box.breadth << "--" << box.height << endl;
return box;
}

// 程序的主函数
int main( )
{
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
double volume = 0.0; // 把体积存储在该变量中

// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);

// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);

// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;

// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;

// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;

// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<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
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
// Week3_Class4.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <string>
#include <iostream>

using namespace std;

// 静态类成员是静态的且不可实例化 一般处理功能性的,比如找贴图 冲加载资源
/*
static class Tools {
static void LoadResources() {

}
static void LoadTexture() {

}
static void ArrayToString() {

}
};
*/

// 一般类构造函数都是公开的否则在函数外部不能实例化对象 类内部的成员没有排序的
// 单例类:只能被实例化一次
// 我们控制的一般只有一个玩家
// 私有化构造函数 在类的内部实例化一次
class PlayerCharacter {
private:
// 声明一个对象指针
static PlayerCharacter* Instance;
private:
// 声明一个私有的构造函数
PlayerCharacter() {}
static void Init() { Instance = new PlayerCharacter(); } //在堆内存中动态实例化一个对象
public:
static PlayerCharacter* GetPlayerCharacterInstance() {
if (Instance == 0) { Init(); } // 直接调用的话Instance是空,判断下如果是空指针就初始化Instance指针对象
return Instance;
}
};

PlayerCharacter* PlayerCharacter::Instance = nullptr;

// 上面的例子在没有对象生成的情况下访问不了 但是使用静态就可以直接通过类名访问了
// 静态函数直接通过类名访问
// 在没有实例化对象之前就可以调用函数,不能再静态函数中访问类的非静态成员 非静态函数中可以调用静态函数

class SkillManager {
private:
static SkillManager* Instance;
public:
static SkillManager* GetSkillManagerInstance() {
if (Instance == 0) {
Instance = new SkillManager();
}
return Instance;
}
};

SkillManager* SkillManager::Instance = nullptr;


class Student {
public:
string Name;
int Age;
float Height;
public:
int GetAge() {
return Age;
}
string GetName() {
return Name;
}
public:
Student() {
cout << "Student 无参构造函数被调用!" << endl << endl;
};
Student(string NewName, int NewAge) {
Name = NewName;
Age = NewAge;
cout << "Student 有两个参数的构造函数被调用!" << endl << endl;
}
Student(string NewName, float NewHeight) {
Name = NewName;
Height = NewHeight;
cout << "Student 有两个参数的构造函数被调用!" << endl << endl;
}
public:
// 在学生类中重新定义小于号的规则,目的是能直接比较两个学生
// 重载<号运算符
bool operator<(const Student& a) {
// 写入具体规则
if (this->Age < a.Age) {
return true;
}
else {
return false;
}
}
bool operator>(const Student& b) {
if (this->Height > b.Height) {
// cout << this->GetName() << "高于" << b.GetName() << endl << endl;
return true;
}
else {
//cout << this->GetName() << "低于" << b.GetName() << endl << endl;
return false;
}
}

static void CompareStudentAge(Student Student1, Student Student2) {
Student1.GetAge() > Student2.GetAge() ? cout << Student1.GetName() << "年龄较大为: " << Student1.GetAge() << endl : cout << Student2.GetName() << "年龄较大为: " << Student2.GetAge() << endl << endl;
}
};

// 结构体可以继承但是一般不会写继承

class Integer {
private:
int Data;
public:
int GetData() {
return Data;
}
void SetData(int a) {
Data = a;
}
public:
Integer() {};
Integer(int a) {
Data = a;
}
public:
// 一元运算符(只需要一个数+ - & *) 二元运算符(需要两个数 + - * / > < ) 三元运算符(三目运算符)
Integer operator-() {
this->Data = -this->Data;
return Integer(Data);
}
};

class Stone {

};

class Water {
private:
double Capacity = 0.0;
public:
friend Water WaterPlus(const Water& w, const Water& A);
friend class Stone;
public:
double GetCapacity() {
return Capacity;
}
public:
Water() {};
Water(double Cap) :Capacity(Cap) {};
public:
Water operator+(const Water& w) {
Water wa;
wa.Capacity = this->Capacity + w.Capacity;
return wa;
}

};

class Fluid {

};

// 类的多继承
class Sea :public Water, public Fluid {

};

// 需要运算符重载的时候只能通过友元函数写
// 友元函数可以直接访问私有属性
// 类也可以有友元类
Water WaterPlus(const Water& W, const Water& A)
{
Water NewW;
NewW.Capacity = W.Capacity + A.Capacity;
return NewW;
}


enum EUIType {
Main,
Package,
Shop
};

// 多态:子类的多态会将父类的同名函数替换掉
class UI {
protected:
float Width = 0.f;
float Length = 0.f;
bool bAllowShow = false;
public:
void SetbAllowShow(bool IsAllow) {
bAllowShow = IsAllow;
}
public:
// virtual 虚函数给指针用的 父类指针指向子类
virtual bool ShowUI() {
if (bAllowShow) {
cout << "Show UI" << endl << endl;
return true;
}
else {
return false;
}
}
};

class PackageUI :public UI {
public:
virtual bool ShowUI() override // override子类重写父类虚函数 指针下有用
{
if (bAllowShow) {
cout << "Show PackageUI" << endl << endl;
return true;
}
else {
return false;
}
}
};

class ShopUI:public UI {
public:
virtual bool ShowUI() override
{
if (bAllowShow) {
cout << "Show ShopUI" << endl << endl;
return true;
}
return false;
}
};

class MainUI :public UI {
public:
virtual bool ShowUI() override
{
if (bAllowShow) {
cout << "Show MainUI" << endl << endl;
return true;
}
return false;
}
};


void CreateUI(EUIType UIType) {
UI* NewUI;
switch (UIType) {
case Main:
NewUI = new MainUI;
break;
case Package:
NewUI = new PackageUI;
break;
case Shop:
NewUI = new ShopUI;
break;
}
}

int mainfdgdfsg()
{
/*
// main 函数调取函数是静态的
// PlayerCharacter::GetPlayerCharacterInstance();
Student Student1("张三",10);
Student Student2("王三", 15);
//Student::CompareStudentAge(Student1, Student2);
cout << (Student1 < Student2) << endl << endl; // C++中非0等价于true
Student Student3("张哈哈",178.5f);
Student Student4("王呵呵",166.8f);
Student3 > Student4; // C++中非0等价于true


// 一元运算符重载
Integer Int(3);
cout << "Int-3:" << Int.GetData() << endl << endl;
cout << "Int_(-3):" << (-Int).GetData() << endl << endl;

// 二元运算符重载
Water a(10.0);
Water b(100.0);
cout << (a + b).GetCapacity()<< endl << endl;

// 类的调用
PackageUI MyPackage;
MyPackage.SetbAllowShow(true);
MyPackage.ShowUI();

// 指针调用写法
PackageUI* MyPackage = new PackageUI;
MyPackage->SetbAllowShow(true);
MyPackage->ShowUI();

// 指针调用写法
UI* MyUI = new UI;
MyUI->SetbAllowShow(true);
MyUI->ShowUI();
*/

// 父类指针指向子类对象
// 有个父类叫UI 子类全部重写虚函数 在游戏中的UI是不同的 商城 main
// 有个枚举存储所有UI 点图标 创建UI函数工作
// 父类创建UI指针可以存储任何一个子类对象的地址 这样调取一个UI函数可设置多种UI显示 点击不同图标即可
UI* MyUI = new PackageUI; // 父类指针子类对象 不匹配
/*
((PackageUI*)(MyUI))->SetbAllowShow(true);
((PackageUI*)(MyUI))->ShowUI();
*/
MyUI->SetbAllowShow(true);
MyUI->ShowUI(); // 如果父类的函数是虚函数 则调用虚函数

// 指针指向哪个对象就调用哪个对象的函数(指针非常灵活,指针里的多态)
// 指针多态指向不同子类的同名虚函数,产生不一样的效果
MyUI = new ShopUI;
MyUI->SetbAllowShow(true);
MyUI->ShowUI();
/*
UI* MyUI01 = new ShopUI;
MyUI01->SetbAllowShow(true);
MyUI01->ShowUI();
*/

return 0;
}

/*
面向对象开发:吃去吃(客人(VIP函数重载)面对服务员 服务员面向厨师和客人 厨师面向服务员) 俺是老板
对象就是类的实例

面向过程开发(所有事情都是一条条完成)做饭吃(都是自己) 孵化器

类:
类的继承
类的多态

虚函数
类的对象的指针

指针调用函数: ->


*/
/*
上午
函数重载
单例

下午
运算符重载
*/




我的作业提交

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// Week3_Class4_HomeWork.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <time.h>

using namespace std;

void Benediction() {
string BenedictionString[] = { "\n你好!\n","\n嘿!\n","\nHello\n","\nHey!\n","\nOh~ Shit!\n","\n雅美蝶!\n" };
int StartInt = 0;
srand((unsigned)time(NULL));
int RandomIndex = StartInt + rand() % (size(BenedictionString) - 1);
cout << BenedictionString[RandomIndex] << endl << endl;
}

enum ESex{
Male,
Female
};

enum ETitle {
Manager, // 管理者
NonManager // 非管理者
};

enum EVIPType {
Normal,
GoldCard,
DiamondCard
};

string ESexArray[] = { "先生","女士" };
string ETitleArray[] = { "管理者","非管理者" };
string EVIPTypeArray[] = { "非会员","白金卡","钻石卡"};


class Human {
public:
string Name;
int* Age;
ESex Sex;
ETitle Title;
EVIPType VIPType;
public:
static int Counter;
public:
friend void CompareVIPType(Human& Customer1, Human& Customer2);
public:
string GetName() {
return Name;
}
int GetAge() {
return *Age;
}
ESex GetSex() {
return Sex;
}
EVIPType GetVIPType() {
return VIPType;
}
void SetName(string NewName) {
Name = NewName;
}
void SetAge(int* NewAge) {
if (Age) {
*Age = *NewAge;
}
}
void SetVIPType(EVIPType NewVIPType) {
VIPType = NewVIPType;
}

public:
Human(){
Age = new int(0);
// cout << "有0个参数的Human构造函数被调用!" << endl << endl;
Counter++;
}
Human(string NewName, int* NewAge) {
Name = NewName;
Age = new int;
*Age = *NewAge;
Counter++;
cout << "有2个参数的Human构造函数被调用!" << endl << endl;
}
Human(string NewName, int* NewAge, EVIPType NewVIPType):Name(NewName), VIPType(NewVIPType) {
Age = new int;
*Age = *NewAge;
Counter++;
cout << "有3个参数的Human构造函数被调用!" << endl << endl;
}
Human(string NewName, int* NewAge,ESex NewSex, EVIPType NewVIPType) :Name(NewName), Sex(NewSex),VIPType(NewVIPType) {
Age = new int;
*Age = *NewAge;
Counter++;
// cout << "有4个参数的Human构造函数被调用!" << endl << endl;
}
Human(string NewName, int* NewAge, ETitle NewTitle, ESex NewSex,EVIPType NewVIPType) {
this->Name = NewName;
this->Age = new int(*NewAge);
this->Title = NewTitle;
this->Sex = NewSex;
this->VIPType = NewVIPType;
Counter++;
cout << "有5个参数的Human构造函数被调用!" << endl << endl;
}

Human(const Human& AHuman) {
Name = AHuman.Name;
Age = new int;
*Age = *AHuman.Age;
Sex = AHuman.Sex;
Title = AHuman.Title;
VIPType = AHuman.VIPType;
Counter++;
}

~Human() {
if (Age) {
delete Age;
Age = 0;
}
Counter--;
}
public:
virtual void SayHello() {
cout << "人类说: " << endl;
Benediction();
}
public:
void test() {
cout << this->VIPType << endl << endl;
}
/*
string operator<(const Human& OtherMan) {
if (OtherMan.VIPType<this->VIPType) {
cout << "您好!" << this->GetName()<< ESexArray[this->GetSex()] << "是" << EVIPTypeArray[this->VIPType] << "会员,优先享有入住服务!" << endl << endl;
}
return "重载<号运算符";
}
*/
};

void CompareVIPType(Human& Customer1, Human& Customer2)
{
if (Customer1.VIPType>Customer2.VIPType) {
cout << "您好!" << Customer1.GetName()<< ESexArray[Customer1.GetSex()] << "是" << EVIPTypeArray[Customer1.VIPType] << "会员,优先享有入住服务!" << Customer2.GetName() << ESexArray[Customer2.GetSex()] << "请稍后!"<< endl << endl;
}
else {
cout << "您好!" << Customer2.GetName() << ESexArray[Customer2.GetSex()] << "是" << EVIPTypeArray[Customer2.VIPType] << "会员,优先享有入住服务!" << Customer1.GetName() << ESexArray[Customer1.GetSex()] << "请稍后!" << endl << endl;
}
}


class Customer:public Human {
public:
Customer(string NewName, int* NewAge, ESex NewSex, EVIPType NewVIPType):Human(NewName, NewAge, NewSex, NewVIPType)
{
this->Name = NewName;
this->Age = new int(*NewAge);
}
public:
virtual void SayHello() override
{
cout << this->GetName() << "说了句: " << endl;
Benediction();
}
public:
void GetRoom() {
cout << "你好,有预约! 预约名:" << this->GetName()<<" 年龄: "<< this->GetAge() << endl << endl;
}

void AskToReceptionDeskLeave() {
cout << this->GetName() << "退房..." << endl << endl;
}

};

class ReceptionDesk:public Human {
public:
void SayHello()
{
cout << "前台迎宾: " << endl;
Benediction();

}
public:
void ServeCustomer(Customer Customer1, Customer Customer2 ) {
cout << "请稍等......" << endl << endl;
CompareVIPType(Customer1, Customer2);
}
void CheckAge(Customer Customer1) {

if (Customer1.GetAge() < 18) {
cout << Customer1.GetName()<< ESexArray[Customer1.GetSex()] << "未成年,不能入住!谢谢配合!" << endl << endl;
}
else {
cout << Customer1.GetName() << ESexArray[Customer1.GetSex()] << "您已成年,可以为您办理入住!" << endl << endl;
}
}

void AskToCleaner() {
cout << "客房! 客房!!! 438 退房..." << endl << endl;
}
};


class Cleaner :public Human {
public:
void SayHello() override
{
cout << "清洁遇到顾客说: " << endl;
Benediction();
}
public:
void CanLeave() {
cout << "已收到!可以离开...." << endl << endl;
}

};

int Human::Counter = 0;

int main()
{
ReceptionDesk ReceptionDesk1;
ReceptionDesk1.SayHello();

int WangAge = 20;
int LiAge = 18;
Customer Wang("王XX", &WangAge, ESex::Male,EVIPType::DiamondCard);
Wang.SayHello();
Wang.GetRoom();
ReceptionDesk1.CheckAge(Wang);
Customer Li("李XX", &LiAge, ESex::Female,EVIPType::GoldCard);
Li.SayHello();
Li.GetRoom();
ReceptionDesk1.CheckAge(Li);

ReceptionDesk1.ServeCustomer(Wang, Li);
cout << endl << endl;
cout << "当前顾客有" << (Human::Counter) - 1 << endl << endl;
cout << "第二天..." << endl << endl << endl;

Li.AskToReceptionDeskLeave();
ReceptionDesk1.AskToCleaner();

Cleaner Cleaner1;
Cleaner1.CanLeave();


return 0;
}


----------本文结束感谢您的阅读----------

本文标题:Unreal Engine 游戏开发学习笔记 20181108

文章作者:XIANVFX

发布时间:2018年11月08日 - 09:11

最后更新:2019年05月21日 - 09:05

原始链接:www.xianvfx.top/UE4/Training/Week3_CPP2/Unreal_Engine_Learning_Notes_W3_4.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

(*❦ω❦) 感谢您的支持! (*❦ω❦)
0%