一、浅谈面向过程和面向对象
C 语言是面向过程的语言,而 C++ 是面向对象的语言。并且当前主流的语言大多数都是面向过程的语言,这足以证实面向过程的语言更适合当前时代的发展。
面向过程在解决题目时主要关注解决题目的过程,也就是解决题目的步骤,把每个步骤抽象成一个函数,然后传入对应的数据调用这些函数一步一步解决题目。而面向对象在解决题目时主要关注题目涉及的对象,把每个对象、相干的数据(成员变量)和能进行的操纵(成员函数)封装成一个类。接着创建每个类的对象实例用来存储数据和实行相应的操纵。
就拿玩游戏闯关打 BOSS 来举例子,如果是面向过程的游戏,那么就需要按照顺序从第一关,第二关,…,第 N 关,BOSS。你需要按照策划设定好的过程一关一关地通过,末了面对 BOSS 。而如果是面向对象的游戏,那么就抽象出来了三个类:玩家、小怪和BOSS,小怪和 BOSS 的设定是如果与玩家的距离在 N 之内大概玩家主动攻击,那么小怪和 BOSS 就会反击。如许游戏就多了许多可能性,比如玩家只通过了一部分关卡就去打 BOSS 大概上来就攻打 BOSS。
通过上述分析可以得出,面向过程的语言关注的是过程,把一个题目分解成多个步骤,调用函数逐步解决。而面向对象是把题目中涉及的对象(包罗其属性和操纵)抽象出来,通过对象之间的交互来完成。
二、C++ 中的结构体(struct)
C++ 中的 struct 中不仅能包含成员变量还能包含成员函数,因为 C++ 中把 struct 当作类来处置惩罚。
1. C++ 中 struct 的利用
下面是一个 C++ 中的门生 struct :
- // 头文件
- #include <iostream>
- // 常量声明
- const int SIZE_NAME = 20;
- const int SIZE_ID = 11;
- // 使用声明
- using std::cout;
- using std::endl;
- // 学生结构声明
- struct Student
- {
- // 成员变量
- char _name[SIZE_NAME];
- size_t _age;
- char ID[SIZE_ID];
- // 成员函数
- void PrintInfo()
- {
- cout << _name << " " << _age << " " << ID << endl;
- }
- };
- int main()
- {
- // 创建结构体变量
- Student zhangsan = { "张三", 18, "2101240002" };
- // 调用成员函数
- zhangsan.PrintInfo();
- return 0;
- }
复制代码 程序的运行结果如下:
从上面的代码中可以看到在创建结构体变量时,直接利用 Student 而不是 C 语言中的 struct Student,这是因为 C++ 中把结构体当作类处置惩罚,而 Student 是一个类名。但是由于 C++ 兼容 C 语言,以是原来 C 语言的 struct Student 语法依旧可以利用。
结构体对象(变量)通过成员运算符(.)来访问成员变量和调用成员函数。
三、C++ 中的类(class)
C++ 中的类由形貌类的成员变量和能对类进行操纵的成员函数组成。
C++ 中的类的创建类似 struct,只不过是把 struct 改成了 class,把结构体名称改为了类名。
class classname
{
//…
};
下面依旧是门生结构体:
- // 头文件
- #include <iostream>
- // 常量声明
- const int SIZE_NAME = 20;
- const int SIZE_ID = 11;
- // 使用声明
- using std::cout;
- using std::endl;
- // 学生类
- class Student
- {
- // 成员变量
- char name[SIZE_NAME];
- size_t age;
- char ID[SIZE_ID];
- // 成员函数
- void Print()
- {
- cout << name << " " << age << " " << ID << endl;
- }
- };
- int main()
- {
- Student zhangsan = { "zhangsan", 18, "2101240002" };
- // 调用成员函数
- zhangsan.Print();
- return 0;
- }
复制代码 可以看到上面的代码与 struct 中的代码除了一个是结构体一个是类,其他都没有区别,但是为什么利用类时编译器报错了呢?
上面的题目就涉及类的封装性和六大默认函数了。
四、类的封装性
什么是封装性?就拿王者荣耀来说,在面向对象设计中,玩家是一个类,该类包含了玩家的属性(金币、点券、对局数等信息)和玩家能进行的操纵(娱乐、匹配、排位等)。那么玩家的属性就是玩家类的成员变量,玩家能进行的操纵就是玩家类的成员函数。玩家可以调用成员函数进行对局,但是玩家不能访问成员变量修改点券,只能通过成员函数(充值)从而间接修改点券。如果可以直接访问玩家属性,那么王者荣耀就无法进行游戏管理和盈利。
类的封装性通过隐蔽类的成员变量,展示类的成员函数,让用户通过成员函数来访问成员变量,如许用户的操纵就比力规范合理。也可以如许理解,类的设计者可以通过类的封装性,让用户可以看见设计者想让用户看见的,也可以让用户看不见设计者不想让用户看见的。
1. 类成员的权限控制关键字
类成员有 public(公有的)、private(私有的)和 protected(受掩护的)。public 成员可以在类外通过类对象进行访问,private 只能在类内进行访问,而在当前的学习阶段只需要把 protected 当作 private 理解就行。protected 在后面的类继承中才会有其他作用。
如今来解释一下为什么上面利用 class 界说的 Student 类不能正常利用,而利用 struct 界说的 Student 却能正常利用。因为如果不显示指明权限,class 默认权限为 private,而 struct 默认权限为 public。
2. 权限控制关键字的利用
下面是利用了权限关键字之后可以正常利用的 Student 类:
虽然如今已经加上了权限关键字,但是上述代码仍存在题目。成员函数 Print() 的权限为 public,以是如今不存在函数调用的题目。而是类对象初始化的题目,这就涉及到六大默认函数中的构造函数了。
五、类的六大默认成员函数介绍
六大默认成员函数函数分别为:构造函数、析构函数、拷贝构造函数、赋值运算符重载、平凡对象和 const 对象取地址运算符重载。
为什么称谓为默认成员函数?是因为如果程序员不显式界说这些函数,那么编译器会主动生成对应的默认函数。
主要需要学习前四个默认函数,而末了两个很少本身重新界说。
六、构造函数
构造函数的作用是在创建类对象的同时对其初始化,而不是创建类对象。且构造函数的函数名和类名类似,没有返回值,也不写 void。
且在初始化对象时,无需利用成员运算符(.),直接在后面接上圆括号然后传入对应参数即可(中心用逗号隔开)。如果没有参数,直接创建对象即可,无需利用圆括号(前提是存在默认构造函数)。
构造函数可以重载,且构造函数是编译器在创建类的对象时根据初始化的数据主动调用的。
1. 利用构造函数
下面利用构造函数纠正 Student 类的末了一个错误。
- // 头文件
- #include <iostream>
- #include <string>
- // 常量声明
- const int SIZE_NAME = 20;
- const int SIZE_ID = 11;
- // 使用声明
- using std::cout;
- using std::endl;
- // Student 类
- class Student
- {
- private:
- char _name[SIZE_NAME];
- size_t _age;
- char _ID[SIZE_ID];
- public:
- // 构造函数
- Student(const char* name, size_t age, const char* ID)
- {
- strcpy(_name, name);
- _age = age;
- strcpy(_ID, ID);
- }
- // 打印信息
- void Print()
- {
- cout << _name << " " << _age << " " << _ID << endl;
- }
- };
- int main()
- {
- // 自动调用构造函数
- Student zhangsan("zhangsan", 18, "2101240002");
- // 打印信息
- zhangsan.Print();
- return 0;
- }
复制代码 程序的运行结果如下:
虽然上述程序可以正常运行,但是仍然存在 bug。如:Student zhangsan;,这条语句没有对应的构造函数,因为创建该对象是没有通报参数。
如上述这种创建参数时不显式通报参数,编译器现实上会去探求默认构造函数。
2. 默认构造函数
默认构造函数就是不需要通报参数的构造函数,可以是全缺省,也可以是无参函数。
当用户未界说任何构造函数时,编译器会生成一个默认构造函数,该函数没有参数,且该函数不对内置类型(int、double等)进行处置惩罚,对自界说类型调用其默认构造函数。
默认构造函数有以下三种:编译器主动生成的默认构造函数、无参构造函数和全缺省构造函数。但是这三种构造函数只能存在一种。
下面是利用了默认构造函数之后的 Student 类。
- // 头文件
- #include <iostream>
- #include <string>
- // 常量声明
- const int SIZE_NAME = 20;
- const int SIZE_ID = 11;
- // 使用声明
- using std::cout;
- using std::endl;
- // Student 类
- class Student
- {
- private:
- char _name[SIZE_NAME];
- size_t _age;
- char _ID[SIZE_ID];
- public:
- // 默认构造函数
- Student()
- {
- strcpy(_name, "小明");
- _age = 18;
- strcpy(_ID, "2101240001");
- }
- // 构造函数
- Student(const char* name, size_t age, const char* ID)
- {
- strcpy(_name, name);
- _age = age;
- strcpy(_ID, ID);
- }
- // 打印信息
- void Print()
- {
- cout << _name << " " << _age << " " << _ID << endl;
- }
- };
- int main()
- {
- // 默认构造函数
- Student xiaoming;
- xiaoming.Print();
- // 构造函数
- Student zhangsan("张三", 19, "2101240002");
- zhangsan.Print();
- return 0;
- }
复制代码 程序的运行结果如下:
在创建小明这个对象的时候,虽然看着像创建了一个未初始化的局部变量,但是现实上编译器为其调用了默认构造函数。
七、类作用域
类有属于本身的作用域,和定名空间 namespace 类似。可以在类中界说与外部全局函数类似的函数名。
跟定名空间 namespace 一个理解就好了,相当于创建了一个新的作用域。只要不再同一个作用域,名称类似就没有题目。当然,函数重载不算。
由于类中是一个新的作用域,以是类中的成员函数在类外界说时,需要显示声明该函数所属的类域。
八、类中函数的声明和界说
如果在类中直接界说函数,那么相当于内联函数(inline),也就是在函数前面加了个关键字 inline。当然也只是给编译器一个发起,并不是直接就是内联函数。
以是通常都是在类中声明函数,在类外界说函数,而在类外界说函数又有所不同。如果在类内声明函数,在类外界说函数,那么在类外界说函数时需要指明该函数属于哪个类,否则编译器会当作全局函数处置惩罚。
九、类的实例化
利用 class 创建一个类时,现实上只是该类的声明,并没有创建空间。参照结构体,利用 struct 创建一个结构体时,只是告诉编译器我要创建一个类型,该类型包含如下内容。然后利用该类型创建具体的变量时,编译器才会开辟空间。
以是当利用类创建具体的对象时,编译器才会分配具体的空间。该过程也叫做类的实例化。
十、类的大小计算
类大小的计算和结构体类似,也存在内存对其。但是计算类大小的时候并不包罗其中的函数,因为每个类的实例化对象都有其各自的成员变量数据,但是调用的都是同一个函数,以是类的函数保存在公共的代码段,全部类的实例化对象均可共享。
- // 头文件
- #include <iostream>
- // 使用声明
- using std::cout;
- using std::endl;
- // Date 类声明
- class Date
- {
- private:
- size_t _year;
- size_t _month;
- size_t _day;
- public:
- Date(size_t year = 1949, size_t month = 10, size_t day = 1); // 默认构造函数
- void Print();
- };
- // Date 类成员函数定义
- Date::Date(size_t year, size_t month, size_t day)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- void Date::Print()
- {
- cout << _year << "-" << _month << "-" << _day << endl;
- }
- int main()
- {
- // 计算 Date 类的大小
- cout << sizeof(Date) << endl;
- return 0;
- }
复制代码 代码的运行结果如下:
由于我的编译器上 size_t 是 64 位的整数,以是结果算出来是 24 个字节。
上面的内存计算还是很简单的,各人本身复习一下内存对其相干的知识。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |