华侨城网站建设,东莞自己建网站哪家强,网站主机测速,gowers wordpress com文章目录 #x1f98d;1. 面向过程和面向对象#x1f9a7;2. 类的引入#x1f436;3. 类的定义#x1f9ae;4. 类的访问控制和封装#x1f356;4.1 访问限定符#x1f356;4.2 封装 #x1f429;5. 类的作用域#x1f405;6. 类的实例化#x1f404;7. 类的大小计算1. 面向过程和面向对象2. 类的引入3. 类的定义4. 类的访问控制和封装4.1 访问限定符4.2 封装 5. 类的作用域6. 类的实例化7. 类的大小计算8. this指针8.1 引子8.2 this指针特性 1. 面向过程和面向对象
C语言是一门面向过程的编程语言面向过程更注重于解决问题的步骤和流程。而C是基于面向对象的关注的是对象之间的交互。我们将数据和相关的功能封装在一起形成对象。每个对象都有自己的属性数据和方法功能。 以做一道青椒肉丝来说 我们需要厨师、青椒、肉丝、锅、铲、油、盐、老抽等物品然后再准备烹饪。先放油油热再放肉丝肉丝炒的差不多之后再放青椒然后再放入盐、老抽最后装盘这些就属于面向过程 在面向对象编程中我们会将青椒肉丝看作一个对象并定义该对象的属性和方法。 对象青椒肉丝 属性青椒、肉片、调味料等方法准备食材、炒菜、调味、出锅等 我们可以创建一个青椒肉丝对象并调用对象的方法来完成烹饪过程。每个方法内部可以封装相应的逻辑和操作。 例如调用青椒肉丝对象的准备食材方法内部会包含切青椒、切肉片和腌制肉片的操作。调用炒菜方法时内部会进行炒肉片和炒青椒的步骤。通过调用对象的方法我们可以按照特定的顺序和逻辑来完成整个烹饪过程。 面向过程适用于简单的、直线式的问题或者强调步骤和算法的场景。面向对象适用于复杂的、需要模拟真实世界的问题或者强调对象之间关系和交互的场景。现在市面上主流的编程语言基本上都是面向对象C、Java、Python等。
2. 类的引入
在C语言中结构体就可以封装多个对象用来描述一些负责的事物。在C中将结构体升级成了类不仅可以定义变量还可以定义函数。
struct Stack
{//方法函数void Init(int defaultCapacity 4){a (int*)malloc(sizeof(int) * 4);if (nullptr a){perror(malloc fail);exit(-1);}capacity defaultCapacity;top 0;}void Push(int x){//...;}void Destory(){free(a);a nullptr;top capacity;}//...//成员变量属性int* a;int top;int capacity;
};
int main()
{//兼容C语言struct Stack s1;//CStack st2;st2.Init();st2.Push(1);st2.Push(2);st2.Destory();return 0;
}3. 类的定义
虽然struct可以定义类但是为了区分C语言C更喜欢用class来定义类。
class定义为类的关键字后面紧跟类名{}为类的主体。
class ClassName {
private:// 成员变量私有DataType memberVariable1;DataType memberVariable2;...public:// 构造函数ClassName(); // 默认构造函数ClassName(parameter1, parameter2, ...); // 带参数的构造函数// 成员函数公有ReturnType memberFunction1(parameter1, parameter2, ...);ReturnType memberFunction2(parameter1, parameter2, ...);...
};使用 class 关键字来定义类后面紧跟着类名通常遵循命名约定使用驼峰命名法。在类定义中我们可以声明成员变量和成员函数。成员变量是类的数据成员表示类的特征或状态。它们在私有部分private进行声明只能在类的内部访问。构造函数是一种特殊的成员函数用于创建和初始化类的对象。在示例中我们展示了默认构造函数和带参数的构造函数的定义。构造函数的名称与类名相同没有返回类型。成员函数是类的行为和操作。它们在公有部分public进行声明并可以包含任意的参数和返回类型。成员函数可以访问类的成员变量执行特定的操作。 类也可以声明和定义分离 类里面定义的函数默认是内联函数但具体也还是编译器决定是否为内联函数。 4. 类的访问控制和封装
4.1 访问限定符
当使用class来定义时程序编译报错我们定义的这些方法无法访问。 这些是因为C中类进行了封装和访问控制用三种修饰符来实现
private私有: 成员被声明为 private 时它们只能在类的内部访问。私有成员对于类的外部是不可见的外部代码无法直接访问它们。public公有: 成员被声明为 public 时它们可以在类的内部和外部被访问。公有成员对外部代码可见可以通过类的对象访问和操作。protected保护: 成员被声明为 protected 时它们与私有成员类似只能在类的内部和派生类中访问。受保护成员对于外部代码是不可见的但可以在派生类中被继承和访问。 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。 class如果不设置访问限定符默认为private struct因为要兼容C语言所以默认为public。 4.2 封装
面向对象的三大特性封装、继承、多态。
在面向对象的封装中类是封装的基本单位类封装了数据成员和成员函数。封装的主要目的是将相关的数据和操作组织在一起形成一个独立的实体对外部隐藏其内部实现细节只提供公共接口。 比如说我们国家的博物馆里面的展品大部分都会设置阻隔我们观众可以参观但是无法直接接触到这些展品。这在一定程度上保护了这些展品同时也规范了观众的行为满足了观众的基本需求。 在程序中封装也是如此通过将数据和操作封装在一起实现了数据的隐藏和保护。 5. 类的作用域
类定义了一个新的作用域类的所有成员都在类的作用域中。在类体外定义成员时需要使用 :: 作用域操作符指明成员属于哪个类域
class MyClass {
public:int publicMember; // 公有成员void PrintInfo();
private:int privateMember; // 私有成员protected:int protectedMember; // 受保护成员
};//指定PrintInfor属于MyClass这个类域
void MyClass::PrintInfo()
{cout MyClass endl;
}int main() {MyClass myObject;myObject.publicMember 10; // 可访问公有成员myObject.PrintInfo();// 以下代码将导致编译错误无法访问私有成员和受保护成员// myObject.privateMember 20;// myObject.protectedMember 30;return 0;
}6. 类的实例化
类的实例化是指根据类的定义创建一个具体的对象使其具备类所定义的属性和行为。
我们定义一个类
class Person
{
public:void showInfo(){cout xxx endl;//...}
private:char* _name;char* _sex;int _age;
};这里并没有实例化↑只是描述出了一个人应该具备的基本属性。
//直接声明对象变量静态实例化对象
Person P1;Person P2;实例化对象 ↑ P1、P2。 类就好比一张食谱食谱上面有许多道菜的做法但没有实际的菜存在所以定义出一个类并没有分配实际的内存空间来存储它。 我们将其实例化就是把这道菜做出来呈现在我们眼前它实际存在占据物理空间。 7. 类的大小计算
class MyClass
{
public:void Print(){cout MyClass endl;}
private:int a;
};int main()
{cout sizeof(MyClass) endl;return 0;
}类中既有成员变量又有成员函数那么这在计算内存的时候是如何计算的呢
// 类中既有成员变量又有成员函数
class A1 {
public:void f1() {}
private:int _a;
};// 类中仅有成员函数
class A2 {
public:void f2() {}
};// 类中什么都没有---空类
class A3
{};int main()
{cout sizeof(A1) endl;cout sizeof(A2) endl;cout sizeof(A3) endl;
}执行该程序得出 4 1 1 我们发现类的大小计算的是该类中的成员变量之和并没有算入函数而没有成员变量或者是空类大小为1byte。
这是因为成员函数是共享给所以该类的使用对象使用的代码并不直接存储在该类中。 打个比方 假设我们有一个小区里面有很多房屋每个房屋都有自己的卧室、客厅、厨房等空间这些就代表着类对象中的数据成员。 但是小区里面会有公共的篮球场、公园等空间这些并没有算在自己房子的大小之内属于公共区域供小区居民共享使用的。 在这个比喻中房屋可以类比为类对象的数据成员而篮球场可以类比为类的成员函数。房屋占用实际的空间我们说房子多大就是自己的房子有多少个平方而篮球场作为公共设施只是为小区居民提供服务不会计算在房子的大小中。 类成员计算大小时也遵循内存对齐规则——内存对齐。
8. this指针
8.1 引子
我们定义一个人的类Person
class Person
{
public:void Init(const std::string n, const std::string sex, int age){_name n;_sex sex;_age age;}void Print(){cout _name _sex _age endl;}
private:std::string _name;std::string _sex;int _age 0;
};int main()
{Person p1, p2;p1.Init(zhangsan, man, 21);p2.Init(cuihua, woman, 20);p1.Print();p2.Print();
}Person类中有Init和Print两个成员函数我们刚才说到成员函数并没有算入类的空间中那当p1调用Init和Print的时候这两个函数是怎么知道是p1呢
C中给每个非静态成员函数增加了一个隐藏的指针参数该指针指向了当前对象函数体的所以成员变量的操作都是通过指针去访问的。这个对于我们用户来说是透明的不需要我们来传递编译器自动完成。
8.2 this指针特性 只能在成员函数内部使用 this指针是成员函数的第一个隐藏指针形参由编译器自动传递 由于this指针是一个形参所以应该就和普通的参数一样存放在栈区里面但是有些编译器会对其进行优化。 以VS2022为例我们发现this指针存放在了rcx中(rcx是x86架构中通用的寄存器之一)。 this 指针是一个常量指针它指向当前对象并不能被修改也不能被显式地赋值给其他指针变量。它始终指向当前对象无法指向其他对象。
有了这些知识储备我们来看一下这段程序的运行结果是什么
class A
{
public:void PrintA(){cout PrintA() endl;}
private:int _a;
};
class B
{
public:void PrintB(){cout _b endl;}
private:int _b;
};
int main()
{A* pa nullptr;B* pb nullptr;pa-PrintA();pb-PrintB();return 0;
}运行发现控制台上打印出了PrintA()随后程序运行崩溃了。
这是因为A和B在调用各自的Print()成员函数时没有发生解引用因为Print()的地址不在对象中A和B作为实参传递给了this指针。但是进入Print()函数后由于A和B都是空所以this指针也为空A没有对齐解引用而B访问了它的成员_b本质上就是this-_b对空指针解引用所以会崩溃。
我们需要知道类是面向对象编程的核心概念类是对象的蓝图定义了对象的属性和行为而对象则是根据类的定义创建的实体。 那本期的分享就到这里啦如果有帮助的话希望三连支持一下我们下期再见如果还有下期的话。