wordpress主题 评论,深圳网站优化运营,静态网站怎么入侵,一键生成短网址1. 类的定义
类是C中的一种自定义类型#xff0c;是某个具体事物或概念的抽象化代码表示#xff0c;通过类的成员#xff08;变量函数/方法#xff09;#xff0c;可以表征出事物或概念的特征。
1.1 类定义的格式
class Stack
{
public:// 成员函数void Init(int n 4)…1. 类的定义
类是C中的一种自定义类型是某个具体事物或概念的抽象化代码表示通过类的成员变量函数/方法可以表征出事物或概念的特征。
1.1 类定义的格式
class Stack
{
public:// 成员函数void Init(int n 4){array (int*)malloc(sizeof(int) * n);if (nullptr array){perror(malloc申请空间失败);return;}capacity n;top 0;}void Push(int x){// ...扩容array[top] x;}int Top(){assert(top 0);return array[top - 1];}void Destroy(){free(array);array nullptr;top capacity 0;}
private:// 成员变量int* array;size_t capacity;size_t top;
}; // 分号不能省略
class为定义类的关键字Stack为类的名字{}中为类的主体注意类定义结束时后面分号不能省 略。类和C语言中的结构体类似类体中内容称为类的成员类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数/类函数。一般来说这些类函数是专门设计来服务于这个类类型的变量对象。
为了区分成员变量一般习惯上成员变量会加一个特殊标识如成员变量前面或者后面加_ 或者 m 开头注意C中这个并不是强制的只是一些惯例具体看公司的要求。
// _成员变量名
int* _array;
size_t _capacity;
size_t _top;// 成员变量名_
int* array_;
size_t capacity_;
size_t top_;// m成员变量名
int* mArray;
size_t mCapacity;
size_t mTop;
C中struct也可以定义类C兼容C中struct的用法同时struct升级成了类明显的变化是 struct中可以定义函数一般情况下我们还是推荐用class定义类。
定义在类中的成员函数默认为inline。
1.2 访问限定符
上面Stack类中的“public”和“private”就是访问限定符除此之外还有“protected”。
他们的作用是限定类成员被访问的权限。 • C一种实现封装的方式用类将对象的属性与方法结合在一块让对象更加完善通过访问权限选择性的将其接口提供给外部的用户使用。 • public修饰的成员在类外可以直接被访问protected和private修饰的成员在类外不能直接被访问protected和private是一样的以后继承章节才能体现出他们的区别。 • 访问权限作用域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为止如果后面没有访问限定符作用域就到 “}”即类结束。 • class定义成员没有被访问限定符修饰时默认为privatestruct默认为public。 • 一般成员变量都会被限制为private/protected需要给别人使用的成员函数会放为public。 习惯上被public修饰的成员统一放到前面被private修饰的成员统一放到后面。
被public修饰的一般是类函数被private修饰的一般是成员变量。
1.3 类域
类定义了一个新的作用域类的所有成员都在类的作用域中在类体外定义成员时需要使用 :: 作 用域操作符指明成员属于哪个类域。
前面提到在类中定义的函数默认为inline函数如果不希望某个函数被当作inline函数则可将类函数的声明与定义分开只在类中声明而在类外进行定义。
class Stack
{
public:// 成员函数void Init(int n 4);void Push(int x);int Top();void Destroy();
private:// 成员变量int* array;size_t capacity;size_t top;
}; // 分号不能省略void Stack::Init(int n 4)
{array (int*)malloc(sizeof(int) * n);if (nullptr array){perror(malloc申请空间失败);return;}capacity n;top 0;
}
void Stack::Push(int x)
{// ...扩容array[top] x;
}
int Stack::Top()
{assert(top 0);return array[top - 1];
}
void Stack::Destroy()
{free(array);array nullptr;top capacity 0;
}
类域影响的是编译的查找规则上面程序中的函数如果不指定类域Stack那么编译器就把这些函数当成全局函数那么编译时找不到array等成员的声明/定义在哪里就会报错。指定类域Stack就是知道这些函数是成员函数当前域找不到的array等成员就会到类域中去查找。
2. 对象的定义实例化
简单来说类只是一种类似于结构体的类型用类类型定义出的变量就是该类的对象。
2.1 实例化的概念
用类类型在物理内存中创建对象的过程称为类实例化出对象。
类是对象进行的一种抽象描述是一个模型一样的东西限定了类有哪些成员变量这些成员变量只是声明没有分配空间用类实例化出对象时才会分配空间。
一个类可以实例化出多个对象实例化出的对象占用实际的物理空间存储类成员变量。打个比方类实例化出对象就像现实中使用建筑设计图建造出房子类就像是设计图设计图规划了有多 少个房间房间大小功能等但是并没有实体的建筑存在也不能住人用设计图修建出房子房 子才能住人。同样类就像设计图一样不能存储数据实例化出的对象分配物理内存存储数据。
以“Date类”为例
class Date
{
public:void Init(int year, int month, int day){_year year;_month month;_day day;}void Print(){cout _year / _month / _day endl;}
private:// 这⾥只是声明没有开空间int _year;int _month;int _day;
};
这里给出了定义“Date类”类型变量的蓝图利用该类进行实例化就可以得到“Date类”类型的变量。
int main()
{// Date类实例化出对象day1和day2Date day1;Date day2;return 0;
}
2.2 this指针
相信读者已经注意到类函数看上去似乎有些奇怪这些函数直接使用了类中的成员变量而没有对应形参的传入那么这些函数怎么知道成员变量是谁的呢。
我们从类函数的调用方式入手
int main()
{Date day1;day1.print(2024, 7, 29);Date day2;day2.print(2004, 12, 18);return 0;
}
因为类函数也是类的成员所以使用成员访问操作符“.”访问对象的成员即可调用类函数。
可以看到类函数的调用是与某个对象绑定在一起的所以类函数能知道成员变量是哪个对象的。
但是在底层上是如何做到的呢
编译器编译后类的成员函数默认都会在形参第一个位置增加一个当前类类型的指针叫做“this指针”。比如Date类的Init的真实原型为
void Init(Date* const this, int year, int month, int day);
所以在调用类函数时当前对象的地址就会通过“this指针”传入函数中函数就能对该对象的成员变量进行操作。
类的成员函数中访问成员变量本质都是通过this指针访问的如Init函数中给_year赋值的语句相当于是 this-_year year;
2.3 对象的大小
我们已经了解过C语言中结构体的大小C语言结构体的大小结构体内存对齐_c语言 struct大小-CSDN博客
相比于结构体类增加了成员函数那么这些成员函数会使实例化出的对象的空间如何变化呢
对于同一个类不同的对象之间成员变量一般不同但是成员函数完全相同。所以没有单独为每一个对象存储成员函数的必要。其次函数被编译后是一段指令对象中没办法存储这些指令 存储在一个单独的区域(代码段)那么对象中非要存储的话也只能是成员函数的指针。同一个函数只有一个地址也没有必要分别存储。最后其实函数指针本身就是不需要存储的函数指针是一个地址调用函数被编译成汇编指令[call 地址] 其实编译器在编译链接时就要找到函数的地址不是在运行时找只有动态多态是在运行时找就需要存储函数地址这个我们以后会讲解。
总结来说每个类的对象的大小只与成员变量有关成员函数不存储在对象中。在此基础上符合内存对齐的原则。