当前位置: 首页 > news >正文

【C++】类和对象(一)

💗个人主页💗
⭐个人专栏——C++学习⭐
💫点击关注🤩一起学习C语言💯💫

目录

  • 导读
  • 1. 面向对象
  • 2. 类
    • 2.1 类的定义
  • 3. 类的访问限定符
  • 4. class与struct定义类的区别
  • 5. 类的封装
  • 6. 类的作用域
  • 7.类的实例化
  • 8. 类的存储方式
  • 9. this指针
  • 10. 题目思考

导读

前面我们学习了C++的入门基础,感兴趣的小伙伴可以点击上方的“C++学习”专栏。今天我们一起来学习类和对象,本篇文章重点了解类。

1. 面向对象

C++是一种面向对象的编程语言,面向对象编程(OOP)是一种软件开发方法,其中程序被组织为对象的集合,这些对象通过相互之间的通信来完成任务。
比如我们洗衣服:

  1. 将衣服放入洗涤桶,倒入适量水与洗衣液,开启定时开关。
  2. 洗衣机定时关闭后放入清水中清掉泡沫放入脱水机中定时脱水。
  3. 脱水完成后拿出衣服即可。

在这里插入图片描述
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

总共有四个对象:人,洗衣机,衣服,洗衣液。
整个过程是四个对象之间交互完成的,人不需要关注洗衣机是如何洗衣甩干的。

在这里插入图片描述

2. 类

类是一种自定义的数据类型,可以定义多个对象(实例)来访问类的成员。类的成员可以是变量(数据成员)或函数(成员函数),用于表示对象的状态和行为。

2.1 类的定义

要定义一个类,需要使用关键字class,然后在类体内定义数据成员和成员函数。类体内也可以定义构造函数、析构函数、访问控制修饰符(public、private、protected)等。

class className
{
// 类体:由成员函数和成员变量组成
};
// 一定要注意后面的分号

在定义类中:

  1. 我们可以把声明和定义全部放在类体中。

需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。

class Person {
public:Person(string name, int age) {this->name = name;this->age = age;}void display() {cout << "Name: " << name << endl;cout << "Age: " << age << endl;}string name;int age;
};int main() {// 创建一个Person对象Person p("Alice", 25);// 调用成员函数display显示对象的信息p.display();return 0;
}
  1. 类声明放在.h文件中,成员函数定义放在.cpp文件中。

注意:成员函数名前需要加类名::

一般情况下,更期望采用第二种方式。
今天为了方便理解,我们采用第一种方式。

3. 类的访问限定符

在C++中,类的成员可以通过访问限定符来控制其对外部的可见性和访问权限,以确保数据的安全性和封装性。

class MyClass {private:int privateVar;public:int publicVar;protected:int protectedVar;
};

在这里插入图片描述

  1. public访问限定符:被声明为public的成员可以在类的内部和外部被访问。

  2. private访问限定符:被声明为private的成员只能在类的内部被访问,外部代码无法直接访问。

  3. protected访问限定符:被声明为protected的成员在类的内部可以被访问,并且在派生类中也可以被访问。

  4. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止

  5. 如果后面没有访问限定符,作用域就到}即类结束。

  6. class的默认访问权限为private,struct为public(因为struct要兼容C)

4. class与struct定义类的区别

在C++中,class和struct都可以用于定义自定义的数据类型,即用户自定义的数据结构。它们的主要区别在于默认的成员访问限定符和默认的继承访问限定符。

在class中,默认的成员访问限定符是private。在struct中,默认的成员访问限定符是public。

class MyClass {int privateVar;   // 默认为privatepublic:int publicVar;void myFunction() {// 在类的内部可以访问private和public成员privateVar = 10;publicVar = 20;}
};struct MyStruct {int publicVar;    // 默认为publicprivate:int privateVar;void myFunction() {// 在结构体的内部可以访问private和public成员privateVar = 10;publicVar = 20;}
};int main() {MyClass myClassObj;myClassObj.publicVar = 30;   // 可以直接访问public成员MyStruct myStructObj;myStructObj.publicVar = 40;  // 可以直接访问public成员return 0;
}

5. 类的封装

面向对象的三大特性:封装、继承、多态。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
封装本质上是一种管理,让用户更方便使用类。

class Circle {
private:double radius;  // 封装的数据public:// 公共接口void setRadius(double r) {if (r >= 0)radius = r;}double getRadius() {return radius;}double calculateArea() {return 3.14 * radius * radius;}
};int main() {Circle c;c.setRadius(5.0);       // 通过公共接口设置半径double area = c.calculateArea();   // 通过公共接口计算面积return 0;
}

在上面的例子中,类Circle封装了一个私有的成员变量radius,并提供了公共的方法setRadius、getRadius和calculateArea来设置半径、获取半径和计算面积。
外部代码无法直接访问和修改radius,只能通过公共接口来操作。这样可以保证radius的有效性和数据的一致性,并提供了简洁的接口来操作数据。

6. 类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。

class Person {
private:string name;int age;public:Person(string name, int age) {this->name = name;this->age = age;}void display();};
// 这里需要指定display是属于Person这个类域
void Person::display()
{cout << "Name: " << name << endl;cout << "Age: " << age << endl;
}
int main() {// 创建一个Person对象Person p("Alice", 25);// 调用成员函数display显示对象的信息p.display();return 0;
}

7.类的实例化

在C++中,类的实例化是通过创建对象来实现的。
如下述代码中,Person类是没有空间的,只有Person类实例化出的对象才有具体的物理空间。

class Person {
private:string name;int age;public:Person(string name, int age) {this->name = name;this->age = age;}void display(){cout << "Name: " << name << endl;cout << "Age: " << age << endl;}};int main() {// 创建Person类对象Person p("Alice", 25);// 调用成员函数display显示对象的信息p.display();return 0;
}

8. 类的存储方式

只保存成员变量,成员函数存放在公共的代码段
在这里插入图片描述

9. this指针

C++中的this指针是一个隐含的指针,指向当前对象的地址。它可以在类的成员函数中使用,用来访问当前对象的成员变量和成员函数。
比如:

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;
};int main()
{Date d1, d2;d1.Init(2024, 1, 30);d2.Init(2022, 1, 29);d1.Print();d2.Print();return 0;
}

Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

:C++编译器给每个“非静态的成员函数“增加了一个隐藏
的指针参数,也就是this指针。
让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。
只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

this指针的使用有以下几个特点:

  1. 在类的非静态成员函数中,this指针被自动地传入函数中,无需显式地声明。可以通过this指针来访问当前对象的成员变量和成员函数。例如,如果在一个成员函数中想要访问成员变量x,可以使用this->x。

  2. this指针是一个常量指针,不能被修改,即不能对this指针进行赋值操作。

  3. this指针可以在成员函数中使用,也可以在成员函数外部使用。在成员函数外部使用时,需要通过对象名来访问this指针,例如obj->this。

  4. 在类的静态成员函数中,由于静态成员函数不属于任何对象,所以不能使用this指针。静态成员函数只能访问静态成员变量和其他静态成员函数。

10. 题目思考

  1. 下面程序编译运行结果是?
    A、编译报错 B、运行崩溃 C、正常运行
class A
{public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}

正常运行

p不发生解引用,因为成员函数的地址不存在对象中,在公共代码区域。这里p为空指针传入print中,然后this接受print地址直接输入。

  1. 下面程序编译运行结果是?
    A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:void PrintA(){cout << _a << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}

运行崩溃:前面一样,this接受的是_a,因为-a是成员变量会对print的p进行解引用

相关文章:

  • 代理IP在游戏中的作用有哪些?
  • MyBaties-增删查改
  • MongoDB日期存储与查询、@Query、嵌套字段查询实战总结
  • 【ArcGIS微课1000例】0099:土地利用变化分析
  • 路飞项目--04
  • 防御保护笔记02
  • ID3算法 决策树学习 Python实现
  • 顺序表的奥秘:高效数据存储与检索
  • LLM之llm-viz:llm-viz(3D可视化GPT风格LLM)的简介、安装和使用方法、案例应用之详细攻略
  • 【leetcode】01背包总结
  • 这些好用小众的知识库软件,快收藏起来
  • docker镜像详解
  • 使用docker部署mongodb
  • 微信抖音快手三合一壁纸小程序源码/后端管理设置功能丰富
  • 设计一个数据库连接池
  • 【Leetcode】104. 二叉树的最大深度
  • 77. Combinations
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • GraphQL学习过程应该是这样的
  • java正则表式的使用
  • Linux中的硬链接与软链接
  • MobX
  • Protobuf3语言指南
  • Python 基础起步 (十) 什么叫函数?
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • Webpack 4 学习01(基础配置)
  • 程序员该如何有效的找工作?
  • 复习Javascript专题(四):js中的深浅拷贝
  • 工作手记之html2canvas使用概述
  • 简单基于spring的redis配置(单机和集群模式)
  • 前嗅ForeSpider中数据浏览界面介绍
  • 如何合理的规划jvm性能调优
  • 数据仓库的几种建模方法
  • 算法---两个栈实现一个队列
  • 2017年360最后一道编程题
  • ​Java并发新构件之Exchanger
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​比特币大跌的 2 个原因
  • #07【面试问题整理】嵌入式软件工程师
  • #mysql 8.0 踩坑日记
  • #VERDI# 关于如何查看FSM状态机的方法
  • #数据结构 笔记一
  • (2)STM32单片机上位机
  • (a /b)*c的值
  • (day18) leetcode 204.计数质数
  • (二刷)代码随想录第15天|层序遍历 226.翻转二叉树 101.对称二叉树2
  • (接上一篇)前端弄一个变量实现点击次数在前端页面实时更新
  • (论文阅读11/100)Fast R-CNN
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (五)c52学习之旅-静态数码管
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)LINQ之路
  • .axf 转化 .bin文件 的方法
  • .Net Core和.Net Standard直观理解
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)