类和对象学习笔记

类和对象

  • 类的定义
  • this指针
  • 类的6个默认成员函数
    • 构造函数
    • 析构函数
    • 拷贝构造函数
    • 赋值运算符重载
      • 赋值运算符重载
      • 运算符重载
      • const成员
    • 取地址操作符重载
    • const取地址操作符重载
  • 初始化列表
  • explicit关键字
  • static成员
  • 匿名对象
  • 友元
  • 内部类
  • 拷贝对象时编译器的优化

类的定义

c++类的定义形式为:

class className
{
pubilic://...
private://...
};

在类的内部可以定义变量和函数,c++可以通过3个访问限定符来限制类的成员的访问权限:
pubilc:在该作用域的成员在类外可以直接访问
private和protected:在该作用域内的成员在类外不能直接访问
c++为了兼容c,就将c的结构体提升成了类,使用struct和class定义类的唯一区别是:class的成员的默认访问权限为private,struct的成员的默认访问权限是public,其他的并无区别。
在类里面定义的成员函数,编译器会将其当成内联函数来处理,但是否展开,最终还是取决于编译器。我们建议将短小的函数直接在类里面定义,其他的函数则声明和定义分离。
对象是类类型的实例化,类类型是对实例化对象的描述,对于一个类实例化出的多个对象来说,除了成员变量用来存储不一样的数据,成员函数都是一样的,因此为了节省空间,对象只保存成员变量,而成员函数则放在公共的代码段。由此,一个类的大小只需计算成员变量的大小即可,其计算方法与计算结构体的大小的方法一致结构体大小的计算。对于空类,编译器为了标识该类的存在,给了其一个字节的大小。

this指针

c++编译器给每一个非静态成员函数增加了一个隐藏的指针参数,该指针指向当前对象,当对象调用成员函数时就可以通过该指针访问该对象的成员变量,该指针由编译器自行传递,不需要用户来完成,用户可以在类里面显示使用this指针。

//定义了一个类
class Student
{
pubilc:void Print()//这里有一个默认this指针,相当于void Print(Student *this){cout<<_name<<_age<<_sex;//cout<<this->_age,显示使用this指针}
private:_name[20]="zhangsan";_age=20;_sex[7]="male"
};int main()
{Student s;//调用打印函数打印学生信息s.Print();//相当于s.Print(&s)return 0;
}

this指针特性:
1.this指针的类型为:类类型*const(如Student *const this),因此不能给this指针赋值。
2.this指针只能在成员函数内部使用。
3.this指针本质上是成员函数的形参,所以对象中不存储this指针(同普通函数参数一样,存放在栈区,VS存放在寄存器)。
4.this指针是成员函数参数列表隐藏着的第一个参数。
5.this指针可以为空。

class Student
{
pubilc:void Print(){cout<<“c++;}
private:_name[20]="zhangsan";_age=20;_sex[7]="male"
};int main()
{Student* s=nullptr;s->Print();//由于成员函数不在对象中,此处不需要解引用,故代码可以正常执行//此时this指针为空return 0;
}
class Student
{
pubilc:void Print(){cout<<_age;}
private:_name[20]="zhangsan";_age=20;_sex[7]="male"
};int main()
{Student*s=nullptr;s->Print();//该代码编译通过,但运行崩溃return 0;
}

类的6个默认成员函数

默认成员函数是当用户没有显式定义时,编译器自动生成的函数。

构造函数

构造函数是名字与类名相同的函数,创建对象时由编译器自动调用,用于给数据成员一个初始值,即初始化对象,该函数在对象整个生命周期内只调用一次。同时构造函数无返回值,可以重载,在调用无参的构造函数时后面不需要跟括号。

class Student
{
pubilc://函数1Student(int height,int weight)//用户显式定义构造函数{_height=height;_weight=weight;}//函数2,无参Student()//构成重载{;}
private:int _height=170;int _weight=60;
};int main()
{Student s1(64,177);//创建时自动调用构造函数1Student s2;//创建时自动调用构造函数2//s2后面不需要跟括号,即不能写成 Student s2(); 否则就成了函数声明
}

当用户没有显式定义构造函数时,编译器会自动生成一个无参的默认构造函数,该默认构造函数对成员变量的处理方式为:对内置类型成员不做处理,对自定义成员调用其默认构造函数 (默认构造函数只有无参的构造函数、全缺省的构造函数、编译器自动生成的构造函数3种)。

class Date
{
public:Date(int year)//用户显式定义了一个参数不是缺省值的构造函数{_year=year;}
private:_year;
};class Student
{
pubilc://用户没有显示定义构造函数,由编译器生成默认构造函数
private:int* p;//不处理int _height=170;//不处理int _weight=60;//不处理Date d1;//调用Date类的默认构造函数//由于Date类没有默认构造函数,故出错
};

默认构造函数只能有一个

class Date
{
public:Date(int year=1){cout << "有参数" << endl;}Date (){cout << "无参数" << endl;}
private:int _year = 60;int _month = 0;int _day = 0;
};class Student
{
public:private:int height;int weigth;Date d;
};int main()
{Date d1(1);//调用有参的构造函数Date d2;//对重载的构造函数调用不明确,出错Student s;//自定义类型调用其默认构造时不明确,出错
}

由上我们可以得知当成员变量都是内置类型时构造函数可以不写,但大多数情况下都要写构造函数。

析构函数

析构函数的功能与构造函数的功能相反,用于对成员变量的资源的清理,在对象销毁时会自动调用析构函数,析构函数不能重载,参数列表为空。

class Date
{
public:Date(){_s=new int;}~Date()//析构函数{delete s;//进行资源清理}
private:int*_s;
}

当用户没有显式定义析构函数时,同构造函数一样,编译器会自动生成一个默认析构函数,该默认析构函数对成员变量的处理方式为:对内置类型成员不做处理,对自定义成员调用其析构函数。

当类里面没有资源申请时,析构函数可以不写,使用编译器生成的默认析构函数就可以了。

拷贝构造函数

用已经存在的类对象创建新对象时会调用拷贝构造函数,如当参数传值为一个类对象、返回一个类对象时等。拷贝构造函数是构造函数的一个重载形式,参数只有一个且必须是类类型对象的引用。

class Date
{
public://参数一定要是引用,如果不是引用,使用拷贝构造函数要进行值拷贝,//就会又去调用拷贝构造函数,从而引发无穷递归Date(const Date& d)//拷贝构造函数,使用const使代码更健壮{_year=d._year;_month=d._month;_day=d._day;}private:int _year = 60;int _month = 0;int _day = 0;
};int main()
{Date d1;Date d2=d1;//调用拷贝构造函数
}

如果用户没有显式定义拷贝构造函数,默认的拷贝构造函数进行的是浅拷贝(值拷贝),对成员变量的处理方式为:对内置类型成员进行浅拷贝,对自定义成员调用其拷贝构造函数。

如果类里面没有涉及到资源的申请时,拷贝构造函数可以不写,但当涉及到资源申请时,拷贝构造函数一定要写,否则是浅拷贝,容易出错。

class Date
{
public:Date()//构造函数{_s=new int;}~Date()//析构函数{delete s;//进行资源清理}
private:int*_s;
}int main()
{Date d1;Date d2=d1;//不会再调用构造函数//以上代码运行时出错//Date类里面进行的是浅拷贝,d1和d2里面的_s指向同一块空间//对象d1、d2销毁时都要调用其析构函数,对同一块空间释放了2次,出错return 0;
}

赋值运算符重载

赋值运算符重载

当要对一个已经创建好的对象进行赋值操作时,需要调用赋值运算符重载函数

class Date
{
public:Date& operator=(const Date& d)//赋值运算符重载{if(this!=&d){_year=d._year;_month=d._month;_day=d._day;}return *this;}
private:_year;_month;_day;
}int main()
{Date d1;Date d2;d2=d1;//调用赋值运算符重载
}

该函数要注意以下4点:
1.为了符合连续赋值,函数需要返回*this,同时为了提高返回的效率,需要用到引用返回。
2.为了提升传参效率和增强代码健壮性,参数应为引用且使用const修饰。
3.要检测是否是自己给自己赋值
原因可以参考这里l1dian11的博客
4.赋值运算符只能重载成类的成员函数,不能重载成全局函数。

当用户没有显式定义时,编译器会自动生成一个默认的运算符重载,以值的方式逐字节拷贝,对成员变量的处理方式为:对内置类型成员直接赋值,对自定义成员调用其对应的赋值运算符重载。

运算符重载

c++除了支持赋值运算符重载外,还支持其他的运算符重载,只不过编译器不会自动生成这些运算符重载,需要用户显式定义。
其有以下几点需要注意:
1.只能重载已有的运算符,不能通过其他符号重载新的运算符,如不能重载@
2.重载类型必须有一个类类型参数(防止用户改变该操作符原来的对内置类型的运算)
3.以下5个运算符不能重载:

.*   ::   sizeof   ?:   .

这里说一下比较特殊的运算符重载:

1.前置++和后置++重载
由于这两个运算符的重载无法直接区分,c++进行了特殊处理:在参数列表增加一个int型参数表示后置++

class Date
{
public:Date operator++()//表示前置++运算符重载{//...}Date operator++(int)//表示后置++运算符重载{//...}
private:_year;_month;_day;
};

2.流插入<<和流提取>>的运算符重载

请添加图片描述

cout是ostream类的对象,cin是istream类的对象

class Date
{
public:ostream& operator<<(ostream& out){//...}private:_year;_month;_day;
};
//用法如下
Date d;
d<<cout;

虽然重载成功了,因为this指针默认占了第一个参数,所以其使用方式很奇怪,不符合我们使用的习惯,因此我们只能将其重载成全局函数。

class Date
{
public://使用友元使类外的函数可以访问类里面的私有成员friend ostream& operator<<(ostream& out,const Date& d);
private:_year;_month;_day;
};friend ostream& operator<<(ostream& out,const Date& d)
{//...
}

const成员

大多数情况下我们并不希望成员函数拥有对类里面的成员进行修改的权限,因此我们希望对this指针使用const进行修饰。

class Date
{
public:void fun() const{//...}以上函数相当于void fun(const Date* const this)//第2个const是this指针自带的
private:_year;_month;_day;
};

我们建议只要成员函数不涉及到对成员变量的修改,后面都要加上const进行修饰。

取地址操作符重载

用于对一个普通对象取地址

class Date
{
public:Date* operator&(){return this;//一般是直接返回this即可//如果写成return 0x11223344;//那么用取地址符获取对象地址时将全都是0x11223344这个地址}
private:_year;_month;_day;
};

这个一般不需要重载,使用编译器默认生成的即可。

const取地址操作符重载

用于对const修饰的对象取地址

class Date
{
public:const Date* operator&() const{return this;//一般是直接返回this即可//如果写成return 0x11223344;//那么用取地址符获取对象地址时将全都是0x11223344这个地址}
private:_year;_month;_day;
};

这个一般也不需要重载,使用编译器默认生成的即可。

初始化列表

类在实例化成对象时,所有的成员变量都会在初始化列表中进行定义并给予变量相对应的值,内置类型如果没有显式地写在初始化列表,则会在初始化列表中给予其一个随机值,对自定义类型,会去调用其默认构造函数。初始化列表和构造函数可以混合使用。
c++11打了补丁,允许其在声明时赋值,这些值其实都是缺省值,用于给初始化列表。

class Date
{
public:Date(int year,int month,int day):_year(2),_month(2){_day=2;}
private:_year=1;_month=1;_day=1;
};int main()
{Date d(3,3,3);//d._year=2,d._month=2,d._day=2;
}

类里面成员变量在类中的声明次序就是初始化列表的初始化顺序,与其在初始化列表中的顺序无关。

explicit关键字

如果类的构造函数只有一个参数或者除第一个参数无默认值其余均有默认值,则该类可以支持隐式转换。

class Date
{
public:Date(int year,int month=1,int day=1){_year=year;_month=month;_day=day;}
private:_year;_month;_day;
};int main()
{Date d=2019;//_year=2019,_month=1,_day=1//将2019转换成Date(2019,1,1),再赋给d
}

c++11还支持多参数的隐式类型转换

class Date
{
public:Date(int year,int month,int day=1){_year=year;_month=month;_day=day;}
private:_year;_month;_day;
};int main()
{Date d={2019,10,11};//_year=2019,_month=10,_day=11
}

有时候我们并不希望这种隐式类型转换的发生,只需在构造函数前面加上explicit关键字即可,但这个关键字不能阻止强制类型转换的发生。

static成员

在类里面以static关键字修饰的成员称为类的静态成员,对于静态成员变量,其只能在类里面进行声明,不能给缺省值。
静态成员有以下特性:
1.静态成员为所有类对象所共享,不属于某个对象,存放在静态区。
2.静态成员变量在类内只是声明,必须要在类外定义,定义时不需加static关键字。
3.静态成员可以直接通过类名::静态成员或者对象.静态成员来访问
4.静态成员没有this指针,不能访问任何非静态成员。
6.静态成员也是类的成员,受public、private、protect访问限定符的限制。

class Date
{
public:explicit Date(int year=1,int month=1,int day=1){++i;_year = year;_month = month;_day = day;}static int i;
private:int _year;int _month;int _day;};int Date::i = 0;int main()
{Date d1;Date d2;Date d3;Date d4;Date d5;cout << Date::i << endl;//i=5;return 0;
}

匿名对象

c++允许匿名对象,可以拥有充当临时变量的作用,其生命周期只在这一行,该行执行完就销毁。

class Date
{
public:Date(int year,int month,int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;};int main()
{Date d1 = Date(1, 2, 3);//匿名对象Date d2 = {1,2,3};//隐式转换return 0;
}

友元

友元分为友元函数和友元类
友元函数是定义在类外部的普通函数,不属于任何类,在类里面声明,可以直接访问类的私有成员,其有以下特性:
1.友元函数不能用const修饰
2.友元函数可以定义在类定义的任何地方声明,不受访问限定符的限制
3.一个函数可以是多个类的友元函数
4.友元函数与普通函数的调用原理相同

友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类里面的私有成员。
友元关系是单向的,没有传递性,不能继承。
虽然友元为访问私有成员提供了便利,但破坏了封装,增加了耦合度,不建议过多使用。

内部类

内部类是指定义在另一个类内部的类,他是一个独立的类,不属于外部类,也不能通过外部类的对象访问内部类的成员,可以认为外部类对内部类没有任何优越的访问权限。但内部类却是外部类的友元类,即内部类可以通过类外部的对象参数访问外部类的所有成员。
需要注意外部类的大小和内部类没有任何关系。

拷贝对象时编译器的优化

大部分编译器会对连续的构造或拷贝构造进行优化,如

连续的构造+构造优化为一个构造
连续的构造+拷贝构造优化为一个构造
连续的拷贝构造+拷贝构造优化为一个拷贝构造
不同的编译器的优化方式和程度不同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/155016.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Bagging集成学习方法的情绪分类预测模型研究(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【每日OJ —— 232.用栈实现队列(栈)】

每日OJ —— 232.用栈实现队列&#xff08;栈&#xff09; 1.题目&#xff1a;232.用栈实现队列&#xff08;栈&#xff09;2.解法2.1.方法讲解2.1.1.算法讲解2.1.2.代码实现2.1.3.提交通过展示 1.题目&#xff1a;232.用栈实现队列&#xff08;栈&#xff09; 2.解法 2.1.方法…

windows上 adb devices有设备 wsl上没有

终于解决了&#xff01;&#xff01;&#xff01;&#xff01; TAT&#xff0c;尝试了很多种办法。 比如WSL中的adb和Windows中的adb版本必须一致&#xff0c;一致也没用&#xff0c;比如使用 ln 建立链接也没用。 这个解决办法的前提是windows中的abd是好用的。 ●在windows…

简单php反序列化实现执行代码

简单php反序列化实现执行代码 反序列化举例 首先定义类和对象&#xff0c;然后输出序列化和反序列化结果看看这是个什么东西 <?phpclass Stu{public $name;public $age;public $sex;public $score;}$stu1 new Stu();$stu1->name "order";$stu1->age …

部署Kubernetes Dashboard

Dashboard简介 Dashboard 是基于网页的 Kubernetes 用户界面。 可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中&#xff0c;也可以对容器应用排错&#xff0c;还能管理集群资源。 Dashboard创建 #创建pods kubectl apply -f https://raw.githubusercontent.com/kub…

北邮22级信通院数电:Verilog-FPGA(10)第十周实验 实现移位寄存器74LS595(仿真方法验证)

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 使用FPGA开发板验证的教程&#xff0c;请参考 北邮…

MySql分区

一、什么是分区 MySQL分区是一种数据库设计和管理技术&#xff0c;它允许你将表分割成独立的、具有特定规则的存储单元。每个分区可以独立地进行管理&#xff0c;包括备份、恢复和优化。分区的主要目的是提高查询性能、简化维护以及实现数据的更有效管理。 以下是MySQL分区的…

高速数据时代的引领者:ETU-LINK 100G DAC全系列技术简介

伴随科技的不断进步&#xff0c;我们正迅速迈向一个高速数据时代。在这个时代&#xff0c;数据的传输速度已经成为发展的重要因素之一。ETU-LINK推出的100G DAC全系列产品&#xff0c;助力高速数据传输领域的新一轮发展。 一、100G DAC全系列产品解析 100G QSFP28 DAC无源高速…

SQL的连接join

一、连接说明 union、intersect等集合运算&#xff0c;它的特征是以 “行” 为单位进行操作&#xff0c;通俗点说&#xff0c;就是进行这些集合运算&#xff0c;会导致记录行数的增减&#xff0c;使用union会增加记录行数&#xff0c;使用 intersect 或 expect 会减少行记录&a…

后端-锁专题:synchronized(java对象结构、锁的类型、锁升级流程...)

文章目录 对象的结构以及大小内存换算java的常见数据类型以及所占字节数分析对象总共占多少字节&#xff0c;各项占多少字节对象头结构 锁类型锁升级流程 对象的结构以及大小内存换算 java的常见数据类型以及所占字节数 String&#xff1a;8字节 64位 int&#xff1a;4字节 …

asp.net勤工助学管理系统VS开发sqlserver数据库web结构c#编程计算机网页项目

一、源码特点 asp.net 勤工助学管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 系统运行视频 https://www.bilibili.com/video/BV1Sz4y1F7GP/ 二、功能介绍 本系统使用Microsoft Visual Studio…

Threejs_10 光线投射技术完成画布三维事件交互

你完成了一个threejs的模型之后&#xff0c;里面有很多东西&#xff0c;你咋知道你点击的是哪个呢&#xff1f;&#xff1f;如何触发你点击的事件呢&#xff1f;再canvas画布中可不能和html事件一样直接使用e.target来完成了哦。如何做到呢&#xff1f; 光线投射实现三维定位 …

自动化物流运输设备模组要选择哪种类型?

在自动化物流运输设备中&#xff0c;选择合适的模组类型取决于具体的运输需求和应用场景。 1、同步带模组&#xff1a;同步带模组是一种低噪音、低成本的物流运输设备&#xff0c;适用于中短距离、轻型货物的运输。它采用同步带传动的方式&#xff0c;具有传动准确、运行稳定、…

12 分布式锁加入看门狗

1、看门狗的流程图 2、看门狗的代码实现 /****类说明&#xff1a;Redis的key-value结构*/ public class LockItem {private final String key;private final String value;public LockItem(String key, String value) {this.key key;this.value value;}public String getKey…

消消乐游戏开发,消除类游戏

消除游戏是一类简单而又充满乐趣的休闲游戏&#xff0c;通过匹配相同的元素来完成任务&#xff0c;其简单直观的玩法吸引了大量玩家。本文将为你介绍设计和开发一款成功的消除游戏的关键步骤。 1. 确定核心玩法机制 消除游戏的核心在于匹配相同的元素。首先&#xff0c;明确定…

MyBatis Generator 插件 详解自动生成代码

MyBatis Generator&#xff08;MBG&#xff09;是MyBatis和iBATIS的代码生成器。可以生成简单CRUD操作的XML配置文件、Mapper文件(DAO接口)、实体类。实际开发中能够有效减少程序员的工作量&#xff0c;甚至不用程序员手动写sql。 它将为所有版本的MyBatis以及版本2.2.0之后的i…

YOLOV5 C++部署的人员检测项目【学习笔记(十一)】

本文为修改后的转载&#xff0c;没有转载链接&#xff0c;所以文章类型暂为原创 文章目录 一、安装Pytorch 及 YOLO v51.1 安装GPU版 pytorch1.2 安装YOLO v5所需依赖 二、YOLO v5训练自定义数据2.1 标注数据2.1.1 安装labelImg2.1.2 标注 2.2 准备数据集2.2.1 组织目录结构2.…

深度学习之三(卷积神经网络--Convolutional Neural Networks,CNNs)

概念 卷积神经网络(Convolutional Neural Networks,CNNs)是一种特殊的神经网络结构,专门用于处理具有网格状结构(如图像、音频)的数据。CNN 在计算机视觉领域取得了巨大成功,广泛应用于图像识别、物体检测、图像生成等任务。以下是 CNN 的主要理论概念: 在数学中,卷…

TeXLive 2023安装教程

TeXLive 2023安装教程 本文介绍最新TeX发行版——TeXLive 2023的安装步骤。如果你想用LaTeX进行写作&#xff0c;那么需要搭建LaTeX环境&#xff1a;可以选择下面两种方案之一进行安装&#xff1a;(1)TeXLive 2023TeXStudio或者(2)TeXLive 2023WinEdt 11。其中TeXLive 2023是由…

[Mac软件]Downie 4.6.34视频下载工具

以下是关于Downie软件的介绍&#xff1a; Downie是一款非常实用的视频下载软件&#xff0c;专门为Mac用户设计。这款软件的使用方法非常简单&#xff0c;只需要将想要下载的视频链接复制到Downie的界面&#xff0c;它就能够自动下载。 Downie最大的特点就是支持的网站非常多&a…