各位好友,欢迎来到本期博客 !今天,正式向 类~~对象 宣战 !接下来,或许很长一段时间,都将接触到大量的
类 对象 !或许是贯穿整个 C++ 很早之前,最先接触的语言是 Java 那时 就已经对 类 对象 产生了不一样的情愫!
后来选择方向上,由于引入了 考研所需 这一参数,亦然选择了 C++ 😊希望,本人的选择并不会感到后悔 !
C++ 将会是本人一生打磨的事业 !本人已在心中决定了这个想法 !!
下面开始讲述,类 对象
-----> 类
经过 C 语言的学习,可以得知 :>
C 语言结构体中只能定义变量。在 C++ 中,结构体内不仅可以定义变量,也可以定义函数。
比如:在前几期的数据结构讲解中,用 C 语言实现栈,结构体中只能定义变量;现以 C++ 方式实现,会发现结构体内可以定义函数 !
如下 :>
文件 “stack.cpp”
#include <iostream>
//using std::cout;
//using std:: endl;
//using namespace std; // 不推荐项目中用这种写法,至于原因,前期博文中有讲解
#include <stdlib.h>
#include <stdbool.h>
typedef int STDataType;
// C++ 中结构体类型升级成了 类
// C++ 兼容 C语言, 以前 数据结构的写法仍然可以实现
struct Stack
{
STDataType* a;
int capacity;
int top;
//结构体内可以定义函数
// 初始化栈区
void Init(int DefaultCapacity = 4) // C++ 优化点,自动补全一些参数,这是很香的
{
a = (STDataType*)malloc(sizeof(STDataType) * DefaultCapacity);
if(a == nullptr) //空指针 于 C++ 中规范化用法
{
perror("maloc::fail");
return ;
}
capcity = DefaultCapacity;
int top = 0;
}
// 销毁栈区
void Destroy()
{
free(a);
a = nullptr; // C++ 空指针规范写法
top = 0;
capacity = 0;
}
// 入栈区元素
void Push(STDataType x)
{
if(top == capacity)
{
STDataType* tamp = (STDataType*)realloc(a, sizeof(STDataType) * capacity * 2);
if(tamp == nullptr)
{
perror("realloc::fail");
return ;
}
a = tamp;
capacity *= 2;
}
a[top++] = x;
}
// 减少栈区内元素个数
void Pop()
{
top--;
}
// 出栈区栈顶元素
STDataType Top()
{
return a[top - 1]; // 若部分好友,对此处不理解,可以参考前几期栈区的讲解
}
// 布尔判空
bool Empty()
{
return top == 0;
}
}; // 分号别忘记了
int main()
{
// 第一种写法:
//struct Stack st1;
//st1.Init();
// 第二种写法:
Stack st2;
st2.Init();
st2.Push(21);
st2.Push(24);
st2.Push(27);
st2.Push(23);
st2.Push(21);
while(!st2.Empty())
{
printf("%d ", st2.Top());
st2.Pop();
}
printf("\n");
st2.Destroy();
return 0;
}
-----> 以下展现彩色图样:
为了好友们,有更好的观感体验,特附上彩色代码图样 :>
运行结果 :>
实现环节 “Stack.cpp”
在 C++ 中,显然结构体内可以支持 定义函数体 !其实,用 C++ 实现一个栈区,还是蛮香的 !
虽然 底层逻辑一样,但是 代码更简洁 !
以上代码,函数体中,默认参数可以省略不写,这也是 C++ 运用结构体的一大优势 !
以上实现,运用了 升级版的结构体来实现栈区 ! 其实, 这仍然缺少 C++ 味道 !上述代码,结构体可以用 class 来替代 !
下面来看,具有 C++ 纯正味道的栈区实现 !
头文件 “Stack.h”
#include <iostream>
// using namespace std;
using std :: cout;
using std :: endl;
#include <stdlib.h>
#include <stdbool.h>
// 类域
// 定义类名 Stack
class Stack
{
// 成员函数
void Init(DefaultCapacity = 4); // 此处可以对参数进行赋值,在定义函数体中则不能,否则会出现重定义
void Push(int x);
void Pop();
int Top();
bool Empty();
void Destroy();
// 成员变量
int capacity;
int top;
}; // 分号别忘记了
实现文件 “Stack.cpp”
#include "Stack.h"
// 相较于放在一个构体内实现栈区,此处需要特别指明,正在定义的函数来自那个类名
void Stack :: Init(int DefaultCapacity) // 此处要注意,别重定义了,意即 赋值
{
a = (int*)malloc(sizeof(int) * DefaultCapacity);
if(a == nullptr)
{
perror("maloc::fail");
return ;
}
capacity = DefaultCapacity;
top = 0;
}
void Stack :: Push(int x)
{
if(top == capacity)
{
int* tamp = (int*)realloc(a, sizeof(int) * capacity * 2);
if(tamp == nullptr)
{
perror("realloc::fail");
return ;
}
a = tamp;
capacity *= 2;
}
a[top++] = x;
}
void Stack :: Pop()
{
top--;
}
int Top()
{
return a[top - 1];
}
bool Empty()
{
return top == 0;
}
void Destroy()
{
free(a);
a = nullptr;
top = capacity = 0;
}
int main()
{
Stack st2;
st2.Init(); // 此处可以传参数,也可以不传参数; 不传参数,使用默认值 在前几期博文中,有讲解 -->函数的重载
st2.Push(21);
st2.Push(24);
st2.Push(27);
st2.Push(23);
st2.Push(21);
while(!st2.Empty())
{
printf("%d ", st2.top());
st2.Pop();
} // 其实这么写,太香了
printf("\n");
st2.Destroy();
return 0;
}
上述代码,便具有了 C++ 味道 !其实,上述栈区的实现,最大的不同 是 “class” 的引入 !
为了好友们,有更好的观感体验,特附上彩色代码图样 :>
头文件 “Stack.h”
实现文件 “Stack.cpp”
现对以上代码进行部分解析 :>
在头文件 “Stack.h” 中,显然是用了 “class” 来替代 “struct” ! 致使,本章节的主打点来了 !
那么 “class” 究竟是什么呢 ?
-----> class 为定义 类的关键字, “ { } ” 范围内 为类的主体,而“类名”是紧跟 class 后面的名字;注意类定义结束后有一个分号不可以省略 !
类的主体内是类的成员 :a. 类中的变量称为类的属性 或成员变量; b. 类中的函数称为类的方法 或成员函数
而类有两种定义:
1.声明和定义全部放在类的主体内,此时,成员函数会被编译器当成 内联函数 进行编译 !
2.类声明放在头文件中,成员函数定义 放在 .cpp 文件中 ;且注意:成员函数 类型之后 需要加上类名 !---> 如下:
请看上述图示的标注,一定别忘记了,类名的加入,以及类名之后的 “ :: ” 域作用限定符
其实,类 也是 一个域,只不过叫做 类域 !
以上两种定义,推荐大家使用第二种 !并不是因为 第一种有内联函数,而是第二种有着熟悉的感觉 !
前几期,数据结构章节 !实现栈区,队列,二叉树等等 !全部都是多文件实现,而且必须有一个头文件用来声明,之后在实现文件“ xxx.c ” 中进行定义 !如此可见,分开写,多文件并行的情况下,代码量更为可观 !也更容易方便快速查找代码,以及管理和维护代码模块区 !
下面再提及一下,变量名命名的素养与规范 !请看下列图示 :>
(1)不规范,代码可读性差劲的命名样例 :>
(2)漂亮,值得称赞,美观的代码命名样例 :>
朋友们,感谢阅读本期博文 !
下一期,为大家带来 访问限定符 “ public ” 讲解,以及继续推进 大类 大对象 😊