【c++】类和对象

类和对象

面向过程和面向对象的初步认识

我们用军事为例,要完成一次作战,需要侦察、后勤保障、战略部署、战术部署...等等

  • 面向过程: 更加关注过程,关注如何侦察(无人机侦察、火力侦察、侦察小组侦察),如何后倾保障、如何战略部署、如何战术部署
  • 面向对象:更关注对象之间的关系,我们现在就可以找侦察参谋、后勤参谋、战术参谋、战略参谋,把他们都聚在指挥部里,而不是更关注过程

前言

在c语言中我们学习过struct,而在c++中,struct升级成了类。现在struct中不止能定义变量,还能定义函数。

类的定义

class 类名
{
   // 类体:由成员函数和成员变量组成
};//分号不能漏

类定义的两种方式

  • 声明和定义全部放在类体中, 成员函数在类中定义的话可能会被当做内联函数
class a
{
public:
    int add(int x,int y)
    {
    return x+y
    }
  int b;
  int c;
}
  • 声明和定义分离
//声明放在.h文件中
class a
{
public:
  int add(int x,int y);
  int b;
  int c;
}
//定义放在.cpp中
int a::add(int x,int y)
{
  return x+y;
}

推荐使用第二种定义方法

类的访问限定符及封装

访问限定符

访问限定符的种类

  • public(公有):可在类外直接被访问
  • protected(保护):不可在类外直接被访问
  • private(私有):不可在类外直接被访问

访问限定符的作用域

从该访问限定符出现的位置到下一访问限定符或者到类结束的位置

c++默认的访问权限

  • class的默认权限是private
  • struct的默认权限是public

class和struct的区别

  • 默认的访问权限不同
  • 在继承和模板参数列表位置有区别(现在还没学到,抱歉QAQ)

封装

  • 将数据和操作数据的方法有机结合,隐藏对象的属性和实现的细节,仅对外公开接口来和对象进行交互
  • 本质上是一种管理,让用户更方便使用类

类作用域

  • 类的所有成员都在类的作用域中,在类外定义成员时需要使用::作用于操作符指明成员属于那个类的作用域

类的存储

  • 成员变量存储在类中
  • 成员函数存储在公共代码区 因为每个成员变量都对应着一个对象,而函数只需要形参便能够实现其功能,不是哪个对象独有的,为了节省空间便存放在公共代码区(毕竟a0对象的加法函数和a1对象的加法函数一模一样,只是参数不同)

类的实例化

  • 用类类型创建对象的过程称作实例化。
  • 类是对对象进行描述用的,类似于设计图,定义一个类时并不会分配实际的内存空间来存储它,当实例化的时候才会。
  • 一个类可以实例化多个对象(根据一个设计图能够造出很多房子)

类对象模型

  • 一个类的大小就是其“成员变量”(不是“成员函数”)之和, 遵守内存对齐原则
  • 空类的大小是1字节,用来表示有这个类

this指针

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

this指针的特性

  • this指针的类型: 类类型* const 指针名,说明不能修改this指针
  • 只能在成员函数内部使用
  • this指针本质是成员函数的形参,而形参存储在栈区,所以this指针不存储于对象中
  • this指针是成员函数一个隐含的指针形参,一般由编译器通过ecx寄存器自动传递,不用用户传递(用户也没这资格)

类的六个默认成员函数

默认成员函数:用户没有显示实现,编译器会自动生成的成员函数。

  1. 构造函数
  2. 析构函数
  3. 拷贝构造函数
  4. 负值重载函数
  5. 普通对象取地址
  6. const对象取地址

构造函数

  • 函数名与类名相同
  • 构造函数支持函数重载
  • 构造函数不带返回值
  • 类实例化时自动调用(防止忘记初始化)
  • 在声明周期内只调用一次
  • 主要任务是初始化对象而不是开空间创建对象
  • 以Date类举例
Date(int year, int month, int day)//日期类的构造函数
{
 if (month > 12 || month < 1 || (day > GetMonthDay(year,month) || day < 1))
 {
  cout<<"非法日期"<<endl;
 }
 cout << "Date(int year, int month, int day)" << endl;
 _year = year;
 _month = month;
 _day = day;
}
  • 如果类中没有显示构造函数,编译器会自动生成一个无参的默认构造函数,该构造函数对内置类型成员不会处理(有的编译器会处理,但不是标准行为),对于自定义类型会自动调用该自定义类型的构造函数。
  • c++11标准中,可以通过在声明内置成员变量时给缺省值来达到使用 编译器生成的默认构造函数对内置类型进行初始化。

默认构造函数的分类

  1. 无参构造函数
  2. 全缺省构造函数
  3. 编译器默认生成的构造函数

初始化列表

  • 构造函数体调用完之后,对象中有了个初始值,但实际上不能成为对对象中的成员变量初始化,构造函数体内的语句只能将其称为赋初值,因为初始化只能初始化一次,而构造函数体内可以多次赋值。
  • 初始化列表:以冒号开头,跟着逗号分隔数据成员列表,每个成员变量后面跟一个放在 括号中的初始值或表达式
  • 初始化列表还是成员函数定义的地方
  • 是一种构造函数
  • 以日期类举例
class Date
{
 public:
  Date(int year, int month, int day)
  : _year(year)
  , _month(month)
  , _day(day)
  {
  //函数体内容(可以不填)
  }
}
关于初始化列表注意事项
  • 每个成员变量在初始化列表中只能出现一次(因为初始化只能初始化一次)
  • 类中包含引用成员变量、const成员变量、自定义类型成员(且该类没有默认构造函数)
  • 尽量使用初始化列表初始化,因为对于自定义类型成员变量,一定会先使用初始化列表初始化
  • 成员变量的初始化顺序是由声明顺序决定的, 与在初始化列表中的出现顺序无关
  • 声明中的缺省值就是给初始化列表用的
  • 初始化列表可以和函数体结合起来用(比如malloc是否开辟成功的检查)
explicit关键字
  • 作用:用于修饰构造函数,防止单个参数或 除了第一个参数外其他参数都有默认值的构造函数发生隐式转换
  • 如果不用explicit修饰构造函数的话,Date d1 = 1为合法操作(1被隐式类型转换成Date的匿名对象,再调用d1的拷贝构造),加上则为非法操作了
class Date
{
 public:
  Date(int year, int month = 0, int day = 0)
  : _year(year)
  , _month(month)
  , _day(day)
  {
  //函数体内容(可以不填)
  }
}

析构函数

  • 函数名为:~类名
  • 无参数
  • 无返回值
  • 在对象生命周期结束的时候自动调用(防止我们忘记销毁对象)
  • 若类中无显式定义编译器会自动生成
  • 以Date类举例
~Date()//析构函数
{
 cout << "~Date()" << endl;
 _year = 0;
 _month = 0;
 _day = 0;
}
  • 同编译器生成的构造函数一样,只对自定义类型操作(调用该自定义类型的析构函数)
  • 当类中有申请内存这一行为时一定要写析构函数,此外就看心情了

拷贝构造函数

  • 只有一个形参(且该形参是本类类型对象的引用,通常会使用const修饰)
  • 在使用已有的对象创建新对象的时候自动调用
  • 是构造函数的一个重载形式
  • 对自定义类型的拷贝一定会调用拷贝构造
  • 参数一定要使用引用否则会引发无穷递归(原因就是上一点)
  • 若没有显示定义,编译器会默认生成拷贝构造。但该拷贝构造会对所有类型进行 浅拷贝,不只针对自定义类型, 浅拷贝十分容易造成野指针的问题(因为两个指针指向同一个空间)
  • 以日期类举例
Date(const Date& d)//拷贝构造
{
 _year = d._year;
 _month = d._month;
 _day = d._day;
}

拷贝构造的应用场景

  1. 使用已存在对象创建新对象
  2. 函数参数类型是类类型对象
  3. 函数的返回值类型是类类型对象

赋值运算符的重载

运算符类型的重载

  • 为了增加代码的可读性
  • 更为方便地操作自定义类型(比较,赋值,输入输出...等)
  • 语法:返回值类型 operator操作符(参数列表)
  • “.*”、“::”、“sizeof”、“?:”、“.” 这五个操作符不能重载
  • 不能通过连接其他符号创建新的操作符
  • 用于内置类型的运算符其含义不会改变
  • 在写运算负值重载函数的时候设计的参数要比实际少一个(因为this指针被隐藏了)
  • 以日期类举例
//
Date& Date:: operator+=(int day)
{
 int maxDay = GetMonthDay(_year, _month);
 _day += day;
 while (_day > maxDay)
 {
  _month++;
  _day -= maxDay;
  if (_month > 12)
  {
   _year++;
   _month = 1;
  }
 }
 return *this;
}
//
Date Date::operator+(int day)
{
 Date tmp = *this;
 tmp += day;
 return tmp;
}
//
Date& Date::operator-= (int day)
{
 while (day)
 {
  if (_day - day < 1)
  {
   day -= _day;
   _month--;
   if (_month < 1)
   {
    _month = 12;
    _year--;
   }
   _day = GetMonthDay(_year, _month);
  }
  else
  {
   _day -= day;
   break;
  }
 }
 return *this;
}
//
Date Date::operator-(int day)
{
 Date tmp = *this;
 tmp -= day;
 return tmp;
}
//
Date& Date:: operator++()//前置++
{
 _day++;
 if (_day > GetMonthDay(_year, _month))
 {
  _day = 1;
  _month++;
  if (_month > 12)
  {
   _month = 1;
   _year++;
  }
 }
 return *this;
}

Date Date::operator++(int)//后置++
{
 Date tmp = *this;
 ++(* this);
 return tmp;
}
Date& Date::operator--()//前置--
{
 _day--;
 if (_day < 1)
 {
  _month--;
  if (_month < 1)
  {
   _month = 12;
   _year--;
  }
  _day = GetMonthDay(_year, _month);
 }
 return *this;
}
//

Date Date::operator--(int)
{
 Date tmp = *this;
 --(*this);
 return tmp;
}
//
bool Date::operator>(const Date& d)
{
 if (_year > d._year)
 {
  return true;
 }
 else if (_year == d._year && _month > d._month)
 {
  return true;
 }
 else if (_year == d._year && _month == d._month && _day > d._day)
 {
  return true;
 }
 return false;
}
//
bool Date::operator==(const Date& d)
{
 return (_year == d._year && _month == d._month && _day == d._day);
}
//
bool Date::operator>=(const Date& d)
{
 return ((*this) > d || (*this) == d);
}
//
bool Date::operator<(const Date& d)
{
 return !((*this) > d || (*this) == d);
}
//
bool Date::operator<=(const Date& d)
{
 return (*this) < d || (*this) == d;
}
//
bool Date::operator!=(const Date& d)
{
 return!((*this) == d);
}
//
int Date::operator-(const Date& d)
{
 Date max = *this;
 Date min = *this;

 if (max < d)
 {
  max = d;
 }
 if (min > d)
 {
  min = d;
 }

 for (int i = 0; 1; i++)
 {
  if ((min += 1) == max)
  {
   return i+1;
  }
 }
}

赋值运算符的重载

  • 赋值运算符的重载格式:
    1. 参数类型为const T&
    1. 返回值类型是 T&
    1. 检测是否给自己复制
    1. 返回*this(否则不能实现连续赋值)
  • 赋值运算符只能重载成类的成员函数而不能重载成全局函数( 因为如果用户未显式定义,编译器会自动生成一个默认赋值运算符重载执行的是浅拷贝,如果定义成全局就会撞到)
  • 涉及到资源管理问题,赋值运算符重载 一定要写

赋值和拷贝构造的概念

  • 赋值:两个已经存在的对象进行拷贝
  • 拷贝构造: 通过一个 已经存在的对象去初始化一个 新的对象

const成员

  • 将const修饰的成员函数称为const成员函数
  • const实际上修饰的是 隐含的this指针,使得类中的任何成员都不能被修改
  • 用法:添加到函数的后面
void Print() const
  • 重载问题
1. void Print() const
2. void Print()

这两个函数构成重载,当我们将this展开,答案显而易见

1. void Print(const Date* this)
2. void Print(Date* this)

取地址以及const取地址操作符的重载

  • 这两个成员函数一般不需要定义,编译器会默认生成(使用的场景不多)
  • 想让别人获得指定内容的时候使用
  • 对于 只读函数,最好都加上const

static成员

  • 用static修饰的成员函数或成员变量被称为静态成员函数、静态成员变量
  • 静态成员变量、函数一定要在类外初始化(因为它们不独属于某一个对象,是公用的),应用案例:统计程序中累计创建了多少个类对象,使用了多少个类对象
  • 存放在静态区
  • 使用类名::静态成员 或者 对象.静态成员来访问
  • 静态成员函数没有隐藏的this指针
  • 静态成员受访问限定符的限制
  • 定义时不添加static关键字
  • 定义的例子
class Solution 
{
private:
    static int _ret;
    static int _i; 
};

int Solution::_ret = 0;
int Solution::_i = 1;

友元

  • 友元分为:友元函数和友元类
  • 友元是一种突破封装的方法,使用时需慎重(谨慎交友)

友元函数

  • 是定义在 类外普通函数,不属于任何类,但需要在类中声明一下(给好友发通行证)
  • 如果A是B类的友元函数,那么A能够访问B中的所有成员
  • 不能使用const修饰友元函数
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用原理和普通函数一样
  • 友元函数可以在类的定义中的任何地方声明,不受访问限定符的限制

友元类

  • 友元关系是单向的(你是我的朋友,我却不是你的朋友(悲))
  • 友元关系不能传递(朋友的朋友不是你的朋友)
  • 友元关系不能继承
class Solution 
{
friend A(int a);//友元的声明
private:
   int _ret;
   int _i; 
};
Solution s;
void A(int a)//友元函数
{
  printf(“%d”,s._i);
}

内部类

  • 定义在一个类里面的类就是内部类
  • 内部类天生是外部类的友元
  • 内部类可以直接访问外部类的static成员,不需要外部类的 对象/类名
  • sizeof(外部类)= 外部类,和内部类没有关系
class Solution 
{
public:
    class Sum
    {
        public:
        Sum()
        {
            _ret += _i;
            _i++;
        }
    };
    int Sum_Solution(int n) 
    {
        Sum a[n];
        return _ret;
    }
private:
    static int _ret;
    static int _i; 
};

匿名对象

  • 和临时对象一样,匿名对象 具有常性
  • 匿名对象的声明周期只有一行
  • const引用会延长匿名对象的生命周期
class Solution 
{
  Solution()
  {
  cout << "Solution" << endl;
  }
private:
   int _ret;
   int _i; 
};
Solution()//匿名对象,声明周期就只有定义的这一行

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue 文件扩展名中 esm 、common 、global 以及 mini 、 dev 、prod 、runtime 的含义

vue 文件扩展名中 esm 、common 、global 以及 mini 、 dev 、prod 、runtime 的含义 vue.js 直接用在 script 标签中的完整版本&#xff08;同时包含编译器 compiler 和运行时 runtime&#xff09;&#xff0c;可以看到源码&#xff0c;适用于开发环境。 这个版本视图可以写在…

微服务的各种边界在架构演进中的作用

演进式架构 在微服务设计和实施的过程中&#xff0c;很多人认为&#xff1a;“将单体拆分成多少个微服务&#xff0c;是微服务的设计重点。”可事实真的是这样吗&#xff1f;其实并非如此&#xff01; Martin Fowler 在提出微服务时&#xff0c;他提到了微服务的一个重要特征—…

【Chat GPT】用 ChatGPT 运行 Python

前言 ChatGPT 是一个基于 GPT-2 模型的人工智能聊天机器人&#xff0c;它可以进行智能对话&#xff0c;同时还支持 Python 编程语言的运行&#xff0c;可以通过 API 接口进行调用。本文将介绍如何使用 ChatGPT 运行 Python 代码&#xff0c;并提供一个实际代码案例。 ChatGPT …

【雕爷学编程】MicroPython动手做(18)——掌控板之声光传感器2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

[php-cos]ThinkPHP项目集成腾讯云储存对象COS

Cos技术文档 1、安装phpSdk 通过composer的方式安装。 1.1 在composer.json中添加 qcloud/cos-sdk-v5: >2.0 "require": {"php": ">7.2.5","topthink/framework": "^6.1.0","topthink/think-orm": "…

Oracle 19c 报ORA-704 ORA-01555故障处理---惜分飞

异常断电导致数据库无法启动,尝试对数据文件进行recover操作,报ORA-00283 ORA-00742 ORA-00312错误,由于redo写丢失无法正常应用 D:\check_db>sqlplus / as sysdba SQL*Plus: Release 19.0.0.0.0 - Production on 星期日 7月 30 07:49:19 2023 Version 19.3.0.0.0 Copyrig…

NoSQL-Redis集群

NoSQL-Redis集群 一、集群&#xff1a;1.单点Redis带来的问题&#xff1a;2.解决&#xff1a;3.集群的介绍&#xff1a;4.集群的优势&#xff1a;5.集群的实现方式&#xff1a; 二、集群的模式&#xff1a;1.类型&#xff1a;2.主从复制&#xff1a; 三、搭建主从复制&#xff…

阿里云服务器全方位介绍_性能功能优势和租用费用

阿里云服务器全方位介绍包括云服务器ECS优势、云服务器租用价格、云服务器使用场景及限制说明&#xff0c;阿里云服务器网分享云服务器ECS介绍、个人和企业免费试用、云服务器活动、云服务器ECS规格、优势、功能及应用场景详细说明&#xff1a; 目录 什么是云服务器ECS&#…

细讲TCP三次握手四次挥手(三)

TCP/IP 协议族 在互联网使用的各种协议中最重要和最著名的就是 TCP/IP 两个协议。现在人们经常提到的 TCP/IP 并不一定是单指 TCP 和 IP 这两个具体的协议&#xff0c;而往往是表示互联网所使用的整个 TCP/IP 协议族。 互联网协议套件&#xff08;英语&#xff1a;Internet Pr…

29_互联网(The Internet)(IP数据包;UDP;TCP;DNS;OSI)

上篇介绍了计算机网络的基础知识&#xff0c;也提到互联网&#xff08;The Internet&#xff09;&#xff0c;本篇将会详细介绍互联网&#xff08;The Internet&#xff09;。 文章目录 1. 互联网&#xff08;The Internet&#xff09;组成及数据包传输过程2. IP 数据包的不足3…

【AGI】Copilot AI编程辅助工具安装教程

1. 基础激活教程 GitHub和OpenAI联合为程序员们送上了编程神器——GitHub Copilot。 但是&#xff0c;Copilot目前不提供公开使用&#xff0c;需要注册账号通过审核&#xff0c;我也提交了申请&#xff1a;这里第一期记录下&#xff0c;开启教程&#xff0c;欢迎大佬们来讨论…

6.3.tensorRT高级(1)-yolov5模型导出、编译到推理(无封装)

目录 前言1. YOLOv5导出2. YOLOv5推理3. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-yolov5模…

医疗小程序:提升服务质量与效率的智能平台

在医疗行业&#xff0c;公司小程序成为提高服务质量、优化管理流程的重要工具。通过医疗小程序&#xff0c;可以方便医疗机构进行信息传播、企业展示等作用&#xff0c;医疗机构也可以医疗小程序提供更便捷的预约服务&#xff0c;优化患者体验。 医疗小程序的好处 提升服务质量…

【时频分析,非线性中频】非线性STFT在瞬时频率估计中的应用(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Cilium 系列-7-Cilium 的 NodePort 实现从 SNAT 改为 DSR

系列文章 Cilium 系列文章 前言 将 Kubernetes 的 CNI 从其他组件切换为 Cilium, 已经可以有效地提升网络的性能。但是通过对 Cilium 不同模式的切换/功能的启用&#xff0c;可以进一步提升 Cilium 的网络性能。具体调优项包括不限于&#xff1a; 启用本地路由 (Native Rou…

Sip网络音频对讲广播模块, sip网络寻呼话筒音频模块

Sip网络音频对讲广播模块&#xff0c; sip网络寻呼话筒音频模块 一、模块介绍 SV-2101VP和 SV-2103VP网络音频对讲广播模块 是一款通用的独立SIP音频功能模块&#xff0c;可以轻松地嵌入到OEM产品中。该模块对来自网络的SIP协议及RTP音频流进行编解码。 该模块支持多种网络协议…

SpringBoot接手JSP项目--【JSB项目实战】

SpringBoot系列文章目录 SpringBoot知识范围-学习步骤【JSB系列之000】 文章目录 SpringBoot系列文章目录[TOC](文章目录) SpringBoot技术很多很多工作之初&#xff0c;面临JSP的老项目我要怎么办环境及工具&#xff1a;项目里可能要用到的技术JSPjstl其它的必要知识 上代码WE…

用Rust生成Ant-Design Table Columns | 京东云技术团队

经常开发表格&#xff0c;是不是已经被手写Ant-Design Table的Columns整烦了&#xff1f; 尤其是ToB项目&#xff0c;表格经常动不动就几十列。每次照着后端给的接口文档一个个配置&#xff0c;太头疼了&#xff0c;主要是有时还会粘错就尴尬了。 那有没有办法能自动生成colu…

Android 面试题 应用程序结构 十

&#x1f525; Intent 传递数据 &#x1f525; Activity、Service、BroadcastReceiver之间的通信载体 Intent 来传递数据。而ContentProvider则是共享文件。 Intent可传递的数据类型&#xff1a; a. 8种基本数据类型&#xff08;boolean byte char short int long float double…

防御第三天

1.总结当堂NAT与双机热备原理&#xff0c;形成思维导图 2.完成课堂NAT与双机热备实验 fw1: <USG6000V1>sy [USG6000V1]int g0/0/0 [USG6000V1-GigabitEthernet0/0/0]ip add 192.168.18.2 24 [USG6000V1-GigabitEthernet0/0/0]service-manage all permit (地址无所谓&…
最新文章