返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++深入刨析类与对象的使用
  • 555
分享到

C++深入刨析类与对象的使用

2024-04-02 19:04:59 555人浏览 薄情痞子
摘要

目录this指针this指针存放在哪nullptr与类类的默认成员函数构造函数意义析构函数拷贝构造运算符重载this指针 现在给出一段代码,实现一个普通的日期 date 的打印: c

this指针

现在给出一段代码,实现一个普通的日期 date 的打印:

class date
{
public:
	void print()
	{
		cout << year<<' ' << month <<' '<< day << endl;
	}
	void init(int y, int m, int d)
	{
		year = y;
		month = m;
		day = d;
	}
private:
	int year;
	int month;
	int day;
};
int main()
{
	date d1;
	date d2;
	date d3;
	d1.init(2022, 5, 15);
	d2.init(2022, 5, 14);
	d3.init(2022, 5, 13);
	d1.print();
	d2.print();
	d3.print();
	return 0;
}

结果如你所想:

那么问题来了,d1,d2,d3在调用类里面的 print 函数时,并没有指明对象或者给出形参,最后结果却能打印出不同的三个结果,这是为什么呢?、

这就是c++语法中的隐藏的 this 指针这里的 this 指针其实就是隐含的形参,这个形参会对函数进行处理,比如刚刚的 print 函数以及他的调用,他们的真面目其实是这样:

void print(date* this)

{ cout<< this->year << ’ ’ << this->month << ’ ’ << this->day << endl; }

d1->init(&d1,2022,5,15);

也就是说所有成员变量前面都会有一个 this 指针修饰(实际上 this 指针是个 const 类型,指针不能修改但指向内容可以修改),使得形参和实参之间架起一座无形的桥梁,进行连结。值得注意的是,这个过程是编译器在捣鼓实现的,不需要我们自己去搞,要是写的时候强行带上 this 指针反而还会报错。

那数据是如何对应上的呢?换个问题就是 print 每次是怎么样对应上 d1,d2,d3的,其实访问成员变量年月日,并不是在访问 private 里的年月日,private 里只是声明并不存在空间的开辟,访问但是同一个类里面的 init 函数从而访问到成员变量。

this指针存放在哪

this 指针存在寄存器里面!

其实编译器在生成程序时加入了获取对象首地址的相关代码。并把获取的首地址存放在了寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。也就是成员函数的其它参数正常都是存放在栈中,而this指针参数则是存放在寄存器中。

类的静态成员函数因为没有this指针这个参数,所以类的静态成员函数也就无法调用类的非静态成员变量。

nullptr与类

如果我定义了一个空值指针,让空值指针分别去访问我类里面的函数与成员变量会怎么样:

class Data
{
public:
	void print()
	{
		cout << "hello" << endl;
	}
	void printa()
	{
		cout << a << endl;
	}
private:
	int a;
};
int main()
{
	Data* n = nullptr;
	n->print();//访问函数
	n->printa();//访问成员变量
	return 0;
}

结果如图:

没错,程序崩溃辣!但是很明显,hello 打印出来了就说明函数的访问是没有问题的,但是是没有办法访问成员变量的。

我们说类里面用空指针访问函数,成员变量结果会不同,原因就是函数在公共代码区,不需要解引用,直接找到函数地址变成 call 地址即可,而成员变量的访问需要解引用自然空指针就会寄。

空指针 nullptr 其实并不是真的“空”,实际上是真实存在的,他指向虚拟进程空间里面地址为 0 的地方,这个 0 地址处是用来程序初始化的,是预留出来的,并不是用来存储数据的。因此空指针一旦指向数据,这个数据就是不被认可的,没有意义的。

类的默认成员函数

类里面什么都没有,就称它为空类,实际上空类中真的什么都没有吗?答案是 NO!任何一个类在默认情况下都会生成 6 个成员函数。

构造函数

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名叫构造,但他的主要任务并不是开辟空间或者创建对象,而是将对象初始化。我们不写,编译器也会生成一个默认无参数的构造函数,但这个默认的构造函数不一定有用,而 C++11打的补丁,针对编辑器自己生成的默认成员函数不初始化的问题,给了缺省值来供默认构造函数使用。

需要注意的是:

  1. 类名与函数名保持一致
  2. 可以不用传参,没有返回值
  3. 对象实例化时编辑器自动调用对应的构造函数
  4. 构造函数支持函数重载
  5. 如果类中没有显式定义构造函数,C++编译器会自动生成一个无参的默认构造函数,如果我们自己显式定义了就不会给出了
  6. 无参的构造函数和全缺省的构造函数都被称为默认构造函数,并且默认构造函数只能有一个

意义

C++将变量分为两种:内置类型(int,char,指针类型等等)和自定义类型(struct/class 去定义的类型对象)

而这正好就是 C++ 语法设计的一个败笔,他会导致

如果有内置类型的成员就得自己写构造函数,比如:

class Stack
{
public:
     void push(int x){
     }
     void pop(){
     }
private:
     Stack stackpush;
     Stack stackpop;
}

该类里面只有自定义类型成员变量,就不需要去写构造函数,默认的构造函数就可以完成了。总结一下就是如果类里面只有自义定类型,就可以用默认构造函数,如果存在内置类型或者需要显示传参初始化就需要自己写构造函数。

析构函数

如果构造函数高速了我们对象是怎么来的,那么析构函数就是在告诉我们对象是怎么走的。析构函数与构造函数功能相反,他并不是完成了对象的销毁,因为局部对象销毁是由编译器来完成,而析构函数是完成对象的一些资源清理工作,他是在对象销毁时自动调用。

再三强调不是销毁对象本身!不是销毁对象本身!所谓的资源清理针对的对象是 malloc,new 或者 fopen 这类的操作进行清理收尾,其实本质上就相当于我们之前的 destroy 函数。

其特征如下:

  1. 析构函数名是在类名前面加上字符 -
  2. 无参数也无返回值
  3. 一个类有且仅有一个析构函数,如果没有显式定义,系统会自动生成析构函数
  4. 对象声明周期结束时,C++编译系统自动调用析构函数

但是注意一个顺序问题:

int main()
{
Stack st1;
Stack st2;
return 0;
}

st1 相比 st2 先构造这没什么问题,但 st2 却比 st1 先析构,析构和构造的顺序是相反的。但他和构造函数一样,对内置类型不处理但是对于自定义类型会去调用。

拷贝构造

有没有可能你会想搞一个和自己一样的对象出来呢?如果想那就该我拷贝构造登场辣!

int main()
{
     Date d1(2022,5,16);
     Date d2(d1);
     return 0;
}

这里的 d2 就是拿 d1 来初始化,所以拷贝构造只有单个形参,该形参是对类类型对象的引用,一般由 const 修饰,再用已存在的类类型对象创建新对象时由编译器自动调用。他实际上是构造函数的一种函数重载,他的参数只要一个,而且必须使用引用传参,因为使用传值会引发无穷递归调用。

在什么情况下系统会调用拷贝构造函数:

(1)用类的一个对象去初始化另一个对象时

(2)当函数的形参是类的对象时(也就是值传递时),如果是引用传递则不会调用

(3)当函数的返回值是类的对象或引用时

C++规定了自义定类型对象,拷贝初始化要调用拷贝构造完成。这就引出来一个问题,比如我们拷贝栈,定义了两个对象 st1 和 st2,假如我写成下面的样子就会出乱子:

Stack st1(1);
Stack st2(st1);

因为是拷贝构造, st2 指向地址和 st1 是一样的,这并不是我们想要的结果,我们传统拷贝是指向同一块空间,而且这里拷贝构造会崩,原因很简单,这里原理上进行的是浅拷贝,默认构造函数会对类里面内置类型进行浅拷贝,值拷贝,对于自义定类型,编译器不知道自义定类型的行为,如何拷贝,什么规则,像 stack 这种类型就需要深拷贝实现,我们后面再去学习

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。

st1 构建完成变成 st2 参数去初始化 st2,st2 一旦拷贝完成就要进行析构,而析构会先执行 st2 ,st2 一旦被清理这块空间就会被销毁,而此时 st1 还在使用这块空间,就会导致内存错误。

运算符重载

说到运算符重载,这里面有几分门道嗷。他是个啥呢?

您可以重定义或重载大部分 C++ 内置的运算符,这样就能使用自定义类型的运算符。重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

说的比较玄学,其实你设想一下这个场景,假如我们给出的日期类有两个成员 d1,d2,我们如果去比较他们能用运算符 ==,<,> 来比较吗,或者我给日期 +、- 一个数可以吗,很明显不行,因为内置类型可以直接使用运算符,但是自义定类型不可以,因此就引入了我们的运算符重载。

运算符重载——函数,函数名:operator +运算符,参数是运算符的操作数,如下:

operator==(Date d1,Date d2)
{
      return d1.year == d2.year
      && d1.month == d2.month
      && d1.day == d2.day
}

细心的你可能会问,内置类型我定义在私有域里面该怎么访问呢?这就有三种方法:

  1. 从根源解决,改成公有类型public(尬活了属于是)
  2. 再写一个公有域的函数来调用私有域的内置类型成员;
  3. C++ 友元(后续会学习到)

先别觉得ez,因为这里他会报错

==是要求的两个参数,我这里也是两个参数没错啊,为什么会参数太多啊?别忘了,操作符还有 默认的形参 this,他被限定为第一个形参,因此我们只需要写一个参数即可:

operator==(Date d)
{
      return year == d.year
      && month == d.month
      && day == d.day
}

编译器遇到 if(d1 == d2) 这样的语句,就会去处理成对应的重载运算符调用 if(d1.operator(d2)),这里编译器时很聪明的,你写的全局他会去调用全局,你写的成员他会去调用成员。而且遇到运算符重载他会在优先去类里面找,没有才回去类外面找,也就是说类的里外同时存在运算符重载函数是可以编译过去的。

注意一下

::

sizeof

?:

.

.*

这五个操作符是不能进行重载的,在选择题中会经常出现。

到此这篇关于C++深入刨析类与对象的使用的文章就介绍到这了,更多相关C++类与对象内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++深入刨析类与对象的使用

本文链接: https://lsjlt.com/news/149741.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++深入刨析类与对象的使用
    目录this指针this指针存放在哪nullptr与类类的默认成员函数构造函数意义析构函数拷贝构造运算符重载this指针 现在给出一段代码,实现一个普通的日期 date 的打印: c...
    99+
    2024-04-02
  • C++深入刨析muduo中的抽象类Poller
    目录Poller是抽象类,Eventloop通过抽象类Poller,引用不同的派生类对象(PollPoller或EpollPoller),调用同名覆盖方法,就可以很方便地去扩展不同的...
    99+
    2024-04-02
  • C++中的类与对象深度解析
    目录初始化列表引论初始化列表explicit关键字引论explicit关键字使用static成员 友元引论友元内部类基础概念内部类的使用补充析构顺序例题总结初始化列表 引论...
    99+
    2024-04-02
  • Java面向对象特性深入刨析封装
    目录1.认识封装2.控制访问权限-访问修饰符3.理解封装必须要知道-包3.1理解包的概念3.2 导入包中的类3.3 自定义包3.4 包的访问权限控制3.5 java中常见的包前面已经...
    99+
    2024-04-02
  • C++深入刨析优先级队列priority_queue的使用
    目录一、priority_queue的介绍二、priority_queue的使用三、priority_queue的模拟实现四、容器适配器4.1、什么是适配器4.2、适配模式4.3、S...
    99+
    2022-11-13
    C++ 优先级队列 priority_queue C++ priority_queue
  • C++深入探究类与对象之对象模型与this指针使用方法
    目录C++对象模型和this指针1 成员变量和成员函数分开存储2 this指针概念3 空指针访问成员函数4 const修饰成员函数C++面向对象的三大特性为:封装、继承、多态 C++...
    99+
    2024-04-02
  • C++中对象&类的深入理解
    什么是对象 任何事物都是一个对象, 也就是传说中的万物皆为对象. 对象的组成: 数据: 描述对象的属性 函数: 描述对象的行为, 根据外界的信息进行相应操作的代码...
    99+
    2024-04-02
  • Java 类与对象:对象导向编程的基石(深入分析)
    : 类:对象的蓝图 类是描述一组具有相同特征和行为的对象的模板。它定义了对象的属性(数据成员)和方法(行为)。类是抽象概念,不能直接实例化。 创建类: class Employee { private String name; ...
    99+
    2024-03-09
    : Java、类、对象、OOP、封装、继承、多态
  • 深入源码解析Python中的对象与类型
    对象 对象, 在C语言是如何实现的? Python中对象分为两类: 定长(int等), 非定长(list/dict等) 所有对象都有一些相同的东西, 源码中定义为PyObject和PyVarObje...
    99+
    2022-06-04
    源码 对象 类型
  • C++类与对象深入之构造函数与析构函数详解
    目录对象的初始化和清理一:构造函数1.1:构造函数的特性1.2:构造函数的分类二:析构函数2.1:概念2.2:特性三:拷贝构造函数3.1:概念3.2:特性3.3:拷贝构造函数调用时机...
    99+
    2024-04-02
  • C++深入讲解类与对象之OOP面向对象编程与封装
    目录1.面向对象编程2.面向过程性编程和面向对象编程3.类的引入4.类的定义4.1类的两种定义方式4.1.1声明和定义全部放在类体中4.2.2.声明和定义不放在类体中5.类的访问限定...
    99+
    2024-04-02
  • 深入浅析Java中的对象与引用
    今天就跟大家聊聊有关深入浅析Java中的对象与引用,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java中的对象和引用详解 在Java中,有一组名词经常一起出现,它们就是“对象和对象...
    99+
    2023-05-31
    java 对象 引用
  • C++可调用对象callableobject深入分析
    目录为什么需要他他究竟是啥他怎样被使用呢本作者一致的观点就是 在任何语言执行的时候先去思考汇编层面能不能做到 如果能做到 那么高级语言才能做到 无论你推出什么新特性 用户态汇编你都是...
    99+
    2024-04-02
  • 深入剖析Python类与对象的内部运作机制
    类与对象 在Python中,类是对象的蓝图,它定义了对象的属性和方法,而对象是类的实例,它具有类的所有属性和方法。 class Person: def __init__(self, name, age): self.na...
    99+
    2024-02-22
    Python 对象 方法 属性 继承 多态
  • 【C++深入浅出】类和对象下篇
    一. 前言         老样子,先来回顾一下上期的内容:上期我们着重学了C++类中的六大默认成员函数,并自己动手实现了一个日期类,相信各位对C++中的类已经有了一定程度的了解。本期就是类和对象的最后一篇啦,终于要结束咯,吧唧吧唧  ...
    99+
    2023-10-10
    c++ 开发语言 初始化列表 static成员 友元 匿名对象 explicit关键字
  • C++浅析类与对象的基础
    目录面向过程和面向对象类的引入访问限定符封装类的作用域类的实例化面向过程和面向对象 类和对象是 C++ 的核心特性 我们之前的C语言就属于面向过程,关注过程,分析求解问题的步骤再通过...
    99+
    2024-04-02
  • C++类与对象的示例分析
    这篇文章主要介绍了C++类与对象的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。类的引入在引入类之前,先来回忆一下C语言中的结构体。结构体是一种自定义类型,可以在其中...
    99+
    2023-06-29
  • 深入浅出分析Java类和对象
    目录一、什么是类二、Java的类和C语言的结构体异同三、类和类的实例化类的声明实例化的对象,成员遵循默认值规则类的实例化静态属性(静态成员变量)四、构造方法创建构造方法this一、什...
    99+
    2024-04-02
  • C++类与对象实例分析
    这篇“C++类与对象实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++类与对象实例分析”文章吧。运算符重载C++语...
    99+
    2023-06-30
  • C语言深入刨析数据结构之栈与链栈的设计与应用
    目录一.栈的定义二.栈的特点三.栈的理解四.链栈引入五.链栈定义六.链栈的结构体设计七.链栈的基本操作7.1链栈的初始化7.2链栈判空7.3链栈入栈7.4链栈出栈7.5取栈顶元素八....
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作