wordpress 数据库 恢复,seo云优化是什么意思,提供设计的的网站,开发工具都有什么C类和对象1 一、类的定义1.类定义格式2.访问限定符3. 类域 二、实例化1.实例化概念2.对象大小 三、this指针四、C和C语言实现Stack对比 以下代码环境在
VS2022。 一、类的定义
1.类定义格式 class 为定义类的关键字#xff0c;Stack 为类的名字#xff0c; { } 中为类的主体… C类和对象1 一、类的定义1.类定义格式2.访问限定符3. 类域 二、实例化1.实例化概念2.对象大小 三、this指针四、C和C语言实现Stack对比 以下代码环境在
VS2022。 一、类的定义
1.类定义格式 class 为定义类的关键字Stack 为类的名字 { } 中为类的主体注意类定义结束时后面分号不能省略。类体中内容称为类的成员类中的变量称为类的属性或成员变量类中的函数称为类的方法或者成员函数。 为了区分成员变量一般习惯上成员变量会加一个特殊标识如成员变量前面或者后面加 “ _ ” 或者 “ m ” 开头注意C中这个并不是强制的只是一些惯例。 C中 struct 也可以定义类C兼容C中 struct 的用法同时 struct 升级成了类明显的变化是 struct 中可以定义函数一般情况下我们还是推荐用 class 定义类。 定义在类里面的成员函数默认加上 inline 。
#include iostreamclass Stack
{
public:// 成员函数void init(int n 4){_arr nullptr;_capacity _size 0;checkCapacity();}int top(){return _arr[_size - 1];}void pop(){--_size;}void push(int x){checkCapacity();_arr[_size] x;}void destroy(){free(_arr);_arr nullptr;_capacity _size 0;}void checkCapacity(){if (_capacity _size){int newCapacity _capacity 0 ? 4 : _capacity * 2;int* temp (int*)realloc(_arr, sizeof(int) * newCapacity);if (temp nullptr){perror(realloc faild);return;}_arr temp;_capacity newCapacity;}}private:// 成员变量int* _arr;int _capacity;int _size;};int main()
{Stack st;st.init();st.push(1);st.push(2);st.push(3);st.destroy();return 0;
}2.访问限定符 C一种实现封装的方式用类将对象的属性与方法结合在一块让对象更加完善通过访问权限选择性的将其接口提供给外部的用户使用。 public 修饰的成员在类外可以直接被访问protected 和 private 修饰的成员在类外不能直接被访问protected 和 private 在这方面的作用是一样的。在继承中才可体现他们的区别 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止如果后面没有访问限定符作用域就到 “ } ” 即类结束。 class 定义成员没有被访问限定符修饰时默认为 privatestruct 默认为 public。 一般成员变量都会被限制为 private / protected需要给别人使用的成员函数会修饰为 public。
class Student
{// 访问限定符public:protected:private:};3. 类域
类定义了一个新的作用域类的所有成员都在类的作用域中在类体外定义成员时需要使用 “ :: ” 作用域操作符指明成员属于哪个类域。类域影响的是编译的查找规则下面程序中 init 如果不指定类域 Stack那么编译器就把 init 当成全局函数那么编译时找不到 _arr 等成员的声明 / 定义在哪里就会报错。指定类域 Stack就是知道 init 是成员函数当前域找不到的 _arr 等成员就会到类域中去查找。
class Stack
{
public:void init(int x);private:int* _arr;int _capacity;int _size;};// 声明和定义分离
void Stack::init(int x)
{//...
}二、实例化
1.实例化概念
用类类型在物理内存中创建对象的过程称为类实例化出对象。类是对象进行一种抽象描述是一个模型一样的东西限定了类有哪些成员变量这些成员变量只是声明没有分配空间用类实例化出对象时才会分配空间。一个类可以实例化出多个对象实例化出的对象占用实际的物理空间存储类成员变量。打个比方类实例化出对象就像现实中使用建筑设计图建造出房子类就像是设计图设计图规划了有多少个房间房间大小功能等但是并没有实体的建筑存在也不能住人用设计图修建出房子房子才能住人。同样类就像设计图一样不能存储数据实例化出的对象才能分配物理内存存储数据。
2.对象大小
类实例化出的每个对象都有独立的数据空间所以对象中肯定包含成员变量。但成员函数不一样首先函数被编译后是一段指令对象中没办法存储这些指令存储在一个单独的区域(代码段)那么对象中非要存储的话只能是成员函数的指针。并且对象中也没有存储其指针的必要Date 实例化 d1 和 d2 两个对象d1 和 d2 都有各自独立的成员变量 _year / _month / _day 存储各自的数据但是 d1 和 d2 的成员函数 init / print 指针却是一样的存储在对象中就浪费了。如果用 Date 实例化 100 个对象那么成员函数指针就重复存储 100 次太浪费了。
#include iostream
using namespace std;class Date
{public:void init(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}void print(){cout _year / _month / _day endl;;}private:// 只是声明没有开空间int _year;int _month;int _day;};int main()
{Date d1;Date d2;d1.init(2024, 8, 2);d1.print();d2.init(2014, 8, 2);d2.print();return 0;
}上面我们分析了对象中只存储成员变量C规定类实例化的对象也要符合内存对齐的规则。
内存对齐规则
第一个成员在与结构体偏移量为 0 的地址处。其他成员变量要对齐到某个数字对齐数的整数倍的地址处。注意对齐数 编译器默认的一个对齐数与该成员大小的较小值。VS中默认的对齐数为 8结构体总大小为最大对齐数所有变量类型最大者与默认对齐参数取最小的整数倍。如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。
博客 (学习总结6)C语言结构体的内存对齐和位段实现 对内存对齐有详细的解释这里不赘述。
没有成员变量的类为表示对象存在给定 1 字节纯粹为了占位标识对象存在。
#include iostream
using namespace std;class Student
{;
};int main()
{Student a;// 大小都为 1 字节cout sizeof(a) endl;cout sizeof(Student) endl;return 0;
}三、this指针 Date 类中有 init 与 print 两个成员函数函数体中没有关于不同对象的区分那当 d1 调用 init 和 print 函数时为分辨应该访问的是 d1 对象还是 d2 对象C给了一个隐含的 this指针 解决这个问题。 编译器编译后类的成员函数默认都会在形参第一个位置增加一个当前类类型的指针叫做 this指针。比如 Date 类的 init 的真实原型为void init(Date* const this, int year, int month, int day) 类的成员函数中访问成员变量本质都是通过 this指针 访问的如 init 函数中给 _year 赋值可改为 this-_year year。 C规定不能在实参和形参的位置显示的写 this 指针(编译时编译器会处理)但是可以在函数体内显示使用 this 指针。 this指针 存放在寄存器中。
class Date
{public://void init(Date* const this, int year 2000, ...)void init(int year 2000, int month 1, int day 1){// 不能修改//this nullptr;//_year year;//_month month;//_day day;this-_year year;this-_month month;this-_day day;}void print(){cout _year / _month / _day endl;;}private:int _year;int _month;int _day;};四、C和C语言实现Stack对比
面向对象三大特性封装、继承、多态下面的对比可以初步体现封装。 通过下面两份代码对比我们发现C实现 Stack 形态上还是发生了挺多的变化底层和逻辑上没啥变化。
C语言版本 Stack详细可参考博客 栈的讲解与实现
#include stdio.h
#include stdlib.h
#include assert.h
#include stdbool.h#define INIT_CAPACITY 4#define EXPANSION_MULTIPLE 2typedef int STDataType;typedef struct Stack
{STDataType* arr;int size;int capacity;
} Stack, * pStack;bool StackEmpty(pStack pst)
{assert(pst);return pst-size 0;
}void StackInit(pStack pst)
{assert(pst);pst-arr NULL;pst-size 0;pst-capacity 0;
}void StackDestroy(pStack pst)
{assert(pst);free(pst-arr);pst-size 0;pst-capacity 0;
}void StackPush(pStack pst, STDataType x)
{assert(pst);if (pst-size pst-capacity){int newCapacity pst-capacity 0 ? INIT_CAPACITY : pst-capacity * EXPANSION_MULTIPLE;STDataType* temp (STDataType*)realloc(pst-arr, newCapacity * sizeof(STDataType));if (temp NULL){perror(realloc failed);return;}pst-arr temp;pst-capacity newCapacity;}pst-arr[pst-size] x;
}void StackPop(pStack pst)
{assert(pst);assert(!StackEmpty(pst));--pst-size;
}STDataType StackTop(pStack pst)
{assert(pst);assert(!StackEmpty(pst));return pst-arr[pst-size - 1];
}int StackSize(pStack pst)
{assert(pst);return pst-size;
}C版本 Stack
#include iostream
#include assert.h
using namespace std;const int INIT_CAPACITY 4;const int EXPANSION_MULTIPLE 2;typedef int STDataType;class Stack
{
public:bool empty();void init();void destroy();void push(STDataType x);void pop();STDataType top();int size();private:STDataType* _arr;int _size;int _capacity;};bool Stack::empty()
{return _size 0;
}void Stack::init()
{_arr nullptr;_size _capacity 0;
}void Stack::destroy()
{free(_arr);_arr nullptr;_size _capacity 0;
}void Stack::push(STDataType x)
{if (_size _capacity){int newCapacity _capacity 0 ? INIT_CAPACITY : _capacity * EXPANSION_MULTIPLE;STDataType* temp (STDataType*)realloc(_arr, newCapacity * sizeof(STDataType));if (temp nullptr){perror(realloc failed);return;}_arr temp;_capacity newCapacity;}_arr[_size] x;
}void Stack::pop()
{assert(!empty());--_size;
}STDataType Stack::top()
{assert(!empty());return _arr[_size - 1];
}int Stack::size()
{return _size;
}int main()
{Stack a;a.init();a.push(1);a.push(2);a.push(3);a.push(4);while (!a.empty()){cout a.top() endl;a.pop();}a.destroy();return 0;
}C中数据都放到了类里面通过访问限定符进行了限制不能再随意通过对象直接修改数据这是C封装的一种体现这个是最重要的变化。这里的封装的本质是一种更严格规范的管理避免出现乱访问修改的问题。当然封装不仅仅是这样的这里就不展开讲了。C中有一些相对方便的语法比如缺省参数成员函数每次不需要传对象地址因为 this 指针隐含的传递了方便了很多使用类型不再需要 typedef 类名就很方便。