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

c++的类和对象(上)

前言

Hello,小伙伴们,今天我们将开启一个新的章节,一起来探寻c++的奥秘。

好,废话不多说我们我们现在开始我们今天的学习!!

1.类的定义

1.1类的定义格式

  • c++为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。类体中的函数称为类的方法或者是成员函数。
  • 为了区分成员变量,一般习惯上成员变量会加一个特殊的标识,如果成员变量前面或者是后面加——或者是m的开头,注意c++中这个是不强制的,只是一些惯例,在一些公司中会有具体的要求。
  • c++中struct也可以定义类,c++兼容c语法中的struct中的用法,同时也对struct中的用法进行了升级,明显的变化是struct中也可以定义函数。一般情况下我们还是更推荐使用class定义类。
  • 定义在类中的成员变量函数,默认情况下都是加上inline的。

我们在这里先定义一个类来演示其效果:

class Date
{ 
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;
private:// 为了区分成员变量,⼀般习惯上成员变量// 会加⼀个特殊标识,如_ 或者 m开头int _year; // year_ m_yearint _month;int _day;
};int main(){Date d;d.Init(2024, 3, 31);return 0;}
}

通过的上面的代码,我们可以直观的看到c原因与c++的区别,定义类的操作上使得c++拥有了更加强大功能,使代码也变得更加的简洁。

我们还可以在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:// 为了区分成员变量,⼀般习惯上成员变量// 会加⼀个特殊标识,如_ 或者 m开头int _year; // year_ m_yearint _month;int _day;
};int main(){Date d;d.Init(2024, 3, 31);d.Print;return 0;}

 1.2访问限定符

  1. c++一种实现封装的方式,用类将对象的属性与方法结合在一起,让对象的属性与方法结合在一起,让对象更加的完善,通过访问权限选择性的将其接口提供给外部的用户使用。
  2. public修饰的成员变量在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private是一样的,到后面的继承章节会着重介绍他们。
  3. 访问权限的作用域从该访问限定符出现的位置开始直到下一个限定符出现,如果后面没有再出现限定访问符号,作用域到}即类截止。
  4. class定义成员的时候没有被限定修饰符修饰时默认设置为private,struct默认设置为public。
  5. 一般成员变量都会被限制为private或者是protected,需要给别人使用时的成员函数会被修饰为public。

 

1.3类域

类定义了一个新的作用域,类的所有成员都在类的作用域中,在类体外定义成员时,需要使用::作用域操作符指明该函数出自那个类域。

类域影响的是编译的查找规则,下面程序Init如果不指定类域Stack,那么编译器就把Init当成全局函数,那么编译时,如果找不到array等成员的声明/定义在哪里,就会出现报错。指定类域·Stack,就是知道Init成员函数,当前域找不到array等成员,就会到类域中去寻找。

 

#include<iostream>
using namespace std;
class Stack
{ public:// 成员函数void Init(int n = 4);private:// 成员变量int* array;size_t capacity;size_t top;
};
// 声明和定义分离,需要指定类域
void Stack::Init(int n)
{array = (int*)malloc(sizeof(int) * n);if (nullptr == array){perror("malloc申请空间失败");return;
} 
capacity = n;
top = 0;
}
int main()
{Stack st;st.Init();return 0;
}

2.实例化

2.1实例化概念

  • 用类类型在物理的内存中创建对象的过程,称之为类实例化出对象。
  • 类时对象进行一种抽象描述,是一个模型一样的东西,限定了类有哪些成员变量,这些成员都是声明没有开辟空间,用类实例化处对象时,才会开辟空间。
  • 一个类可以实例化出多少个对象,实例化出的对象占用物理空间,存储类成员变量。打个比方:类实例化出对象就像现实中使用建造图建造房子,类就是设计图,设计图规划了有多少个房间,房间的大小和功能等,但并没有实体的材料建造成型,不能使用,用设计图建造出房子才能住人。同样,类就是像设计图一样的东西,不能存储数据,实例化出的对象则可以分配物理内存来存储数据。

#include<iostream>
using namespace std;
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
Date d1;
Date d2;
d1.Init(2024, 3, 31);
d1.Print();
d2.Init(2024, 7, 5);
d2.Print();
return 0;
}

 2.2对象的大小

分析一下类对象中的那些成员呢?类实例化的每一个对象,都拥有独立的空间,,所以对象中肯定包含成员变量,那么成员函数是否包含其中呢?

首先函数被编译后只是一段指令,对象没有办法在存储,这些指令存储在一个特定的区域(代码段),那么对象中非要存储的话,只能是成员函数的指针.在分析一下,对象中是否有存储指针的必要,Date实例化d1,d2两个对象,d1\d2都有自己独立的成员变量_year/_month/_day储存在各自的数据,互不干扰,但是d1和d2的的成员函数的指针确实一样的,存储在类中就有点浪费空间了。

接下来对象的大小计算还是会涉及我们之前在结构体学到的内存对齐,这里我们就不再赘述,还不是很清楚的同学可以再去看看我之前写的这篇文章: http://t.csdnimg.cn/oNC9Y

 这里我们演示一个特殊的按例:

/ 计算⼀下A/B/C实例化的对象是多⼤?
class A
{ 
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;
int _i;
};
class B
{ 
public:
void Print()
{
//...
}
};
class C
{};
int main()
{
A a;
B b;
C c;
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
cout << sizeof(c) << endl;
return 0;
}

运行一下,我们来看看会得到怎样的结果:

 上面的程序我们可以看到运行的结果是,B和C的类对象大小是1,为什么没有对象成员但还是会占用存储空间呢?

因为如果一个字节都不给,怎么来表示对象存在过呢?所以这里给了一个字节,存粹就是为了站位标识对象的存在。

3.this指针

  • Date类中有Init函数和Print函数,函数体中没有关于不同对象的区分,那当d1调用Init和Print函数时,该函数是如何知道该访问的是d1的对象还是d2的对象呢?这里就要看c++给的一个隐含的this指针解决了这里的问题。
  • 编译器编译后,类的成员函数默认都会在形参的第一个位置,增加一个当前类类型的指针,叫做this指针。
  • 类中的成员函数访问成员变量是,本质都是通过this指针访问的,入Init函数中给_year赋值,this->_year = year.
  • c++规定不能在实参和形参的位置显示this指针(编译时编译器会进行处理),但是在函数体内可以将this指针显示使用。 
#include<iostream>
using namespace std;
class Date
{ 
public:
// void Init(Date* const this, int year, int month, int day)
void Init(int year, int month, int day)
{
// 编译报错:error C2106: “=”: 左操作数必须为左值
// this = nullptr;
// this->_year = year;
_year = year;
this->_month = month;
this->_day = day;
} 
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
// 这⾥只是声明,没有开空间
int _year;
int _month;
int _day;
};
int main()
{
// Date类实例化出对象d1和d2
Date d1;
Date d2;
// d1.Init(&d1, 2024, 3, 31);
d1.Init(2024, 3, 31);
d1.Print();
d2.Init(2024, 7, 5);
d2.Print();
return 0;
}

好,今天的学习就到这里,咱们下期再见,拜拜!!! 

相关文章:

  • 鸿蒙(API 12 Beta2版)媒体开发【处理音频焦点事件】
  • 【电路笔记】-无源衰减器
  • websocket投送
  • Go语言本机多版本管理
  • 鸿蒙AI功能开发【hiai引擎框架-人脸比对】 基础视觉服务
  • 【OpenCV C++20 学习笔记】霍夫圆形变换-Hough Circle Transform
  • Can‘t import openai in Node
  • 2024 某公司python 面试真题
  • C# Unity 面向对象补全计划 泛型约束
  • 代码随想录算法训练营第三十九天 | 322. 零钱兑换、279.完全平方数、139.单词拆分、多重背包理论基础、背包问题总结
  • 到底是低度还是高度的白酒对身体的伤害更大?
  • Linux网络编程3
  • 20240807 每日AI必读资讯
  • UNI-APP_点击,长按,触摸,结束触摸事件
  • 【C/C++笔记】:易错难点3 (二叉树)
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • Java应用性能调优
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • React+TypeScript入门
  • Twitter赢在开放,三年创造奇迹
  • Vue学习第二天
  • 欢迎参加第二届中国游戏开发者大会
  • 如何利用MongoDB打造TOP榜小程序
  • 手写双向链表LinkedList的几个常用功能
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • Python 之网络式编程
  • 第二十章:异步和文件I/O.(二十三)
  • 进程与线程(三)——进程/线程间通信
  • ​​​​​​​开发面试“八股文”:助力还是阻力?
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • (2024最新)CentOS 7上在线安装MySQL 5.7|喂饭级教程
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (三)mysql_MYSQL(三)
  • (一)基于IDEA的JAVA基础1
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (译)计算距离、方位和更多经纬度之间的点
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (转)负载均衡,回话保持,cookie
  • (转载)从 Java 代码到 Java 堆
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • ./configure、make、make install 命令
  • .NET Framework 4.6.2改进了WPF和安全性
  • .net oracle 连接超时_Mysql连接数据库异常汇总【必收藏】
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .NET 解决重复提交问题
  • .NET 命令行参数包含应用程序路径吗?
  • /etc/sudoers (root权限管理)
  • @DataRedisTest测试redis从未如此丝滑
  • [ vulhub漏洞复现篇 ] JBOSS AS 4.x以下反序列化远程代码执行漏洞CVE-2017-7504
  • [android] 练习PopupWindow实现对话框
  • [C++ 从入门到精通] 12.重载运算符、赋值运算符重载、析构函数
  • [CTO札记]盛大文学公司名称对联