C++基础知识(四:类的学习)

类指的就是对同一类对象,把所有的属性都封装起来,你也可以把类看成一个高级版的结构体。

【1】定义

class 类名
{
访问权限:
    成员属性;
访问权限:
    成员方法;
}访问权限:
public:共有的,类内、类外和子类中都可以访问
private:私有的,类内可以访问,类外和子类中都不能访问,类中默认是私有权限
protected:受保护的,类内和子类中可以访问,类外不可以访问(继承再说)访问权限,是针对于一个类来说的

【2】类和结构体的区别

  1. 类的封装性比结构体更好,类中默认是私有权限,结构体中默认是共有权限
  2. 结构体默认是公有继承,类默认是私有继承
  3. C++中类就是由结构体演变来的
  4. 结构体一般用于实现某种数据结构时,类一般用于描述一类对象的性质

【3】this指针**

每一个类中的非静态成员函数,都有一个this指针,指向调用者,(非静态成员数隐藏 的形参)

谁调用this就指向谁哪一个类对象调用成员函数,就会用该类对象的首地址,初始化形参this

原型:类类型  *const this; ----->指针的指向不能修改

需要使用this指针的场合

  1. 当形参和成员属性同名
  2. 拷贝赋值函数,需要返回自身的引用
#include <iostream>using namespace std;
class Rec
{
private:int len;int wid;
public:void set(int l,int w);  //设置长和宽void show();   //输出面积和周长int get_l();     //获取长和宽int get_wid();
};void Rec::set(int len, int wid)   //r1.set()
{this->len = len;this->wid = wid;
}void Rec::show()
{
    cout << "周长:" << (len+wid)*2 << endl;
    cout << "面积:" << len*wid << endl;
}int Rec::get_l()
{return len;
}int Rec::get_wid()
{return wid;
}
int main()
{
    Rec r1;  //r1是一个类对象,实例化了一个类对象r1
    r1.set(9,2);
    Rec r2;
    r2.set(9,2);
    cout << "&r1=" << &r1 << endl;return 0;
}

【4】类中的特殊成员函数

特殊的构造函数都是public权限

类中,会默认提供一些特殊的成员函数:构造函数、析构函数、拷贝构造函数、拷贝赋值函数

【5】构造函数

构造函数支持函数重载

构造函数,会在实例化类对象时,系统默认调用无参构造;

如果用户手动定义出了构造函数,系统将不再提供构造函数

类名()
{//函数体
}

调用时机

栈区:实例化类对象时,自动调用

堆区:什么时候使用new申请空间,什么时候调用构造函数

当提供构造函数后

ii)构造函数提供了初始化列表的机制

如果在函数体内部,给成员属性赋值,是一个赋值的过程,不是初始化的过程

类名():成员属性1(形参的值1),成员属性2(形参的值)`````在函数头后面,使用:引出初始化列表,每个成员属性以,分隔,()里面是形参,外面是成员属性

iii)需要使用初始化列表的情况

  1. 形参和成员属性同名
  2. 类中有引用成员时,必须使用初始化列表
#include <iostream>using namespace std;
class Stu
{int age;float high;int &score;
public://构造函数支持函数重载Stu(int age,float high,int a):age(age),high(high),score(a){
        cout << "Stu的有参构造" << endl;}
};int main()
{//Stu s;int n1 = 90;
    Stu s1(18,9,n1);    //在栈区
    Stu *p;//p = new Stu;   //在堆区申请了Stu类对象的空间return 0;
}
  1. 类中有const修饰的成员时,必须使用初始化列表
#include <iostream>using namespace std;
class Stu
{int age;float high;const int score;
public:
//    Stu()
//    {
//        cout << "Stu的无参构造函数" << endl;
//    }//构造函数支持函数重载Stu(int age,float high,int a):age(age),high(high),score(a){
        cout << "Stu的有参构造" << endl;}
};int main()
{//Stu s;int n1 = 90;
    Stu s1(18,9,89);    //在栈区
    Stu *p;//p = new Stu;   //在堆区申请了Stu类对象的空间return 0;
}
  1. 类中含有其他类的子对象时,必须使用初始化列表(类的包含关系)

(如果另一个类只有有参构造需要在初始化列表中宏显性调用,如果另一个类有无参构造,可以不写初始化列表)

                类的包含关系

#include <iostream>using namespace std;
class Per
{
    string name;
public:Per(string name){this->name = name;
        cout << "Per的有参构造" << endl;}
};class Stu
{int age;float high;int score;
    Per p1;   //Per类只有有参构造函数
public:Stu():p1("zhangsan"){
        cout << "Stu的无参构造函数" << endl;}//构造函数支持函数重载Stu(int age,float high,int a,string name):p1(name){this->age = age;this->high = high;this->score = a;
        cout << "Stu的有参构造" << endl;}
};int main()
{
    Stu s;int n1 = 90;
    Stu s1(18,9,89,"lisi");    //在栈区return 0;
}

【6】析构函数

不支持函数重载

在类对象空间消亡时,系统自动调用

i)格式

~类名()
{//函数体
}

ii)调用时机

栈区:对象消亡时,自动调用
堆区:什么时候delete,什么时候调用

构造函数和析构函数调用的时机:

先构造的后析构,后构造的先析构

iii)需要显性写出析构函数的场景

类中有指针成员,并且指针成员,指向堆区的空间

#include <iostream>using namespace std;
class Stu
{
    string name;int *p;
public:Stu():p(new int)   //保证指针成员,指向堆区的空间{
        cout << "堆区申请的空间为:" << p << endl;
        cout << "Stu的无参构造" << endl;}
//    Stu(string name,int p):name(name),p(new int(p))
//    {
//        cout << "Stu的有参构造" << endl;
//    }~Stu(){
        cout << "准备释放堆区的空间:" << p << endl;delete p;
        cout << "Stu的析构函数" << endl;}};int main()
{
    Stu s1;return 0;
}

【7】拷贝构造函数

利用一个类对象,给另一个类对象初始化时,自动调用拷贝构造函数

如果自己实现了拷贝构造,系统不再提供默认的拷贝构造

i)格式

类名(同类对象的引用)
{
   //函数体
}

ii)使用

#include <iostream>using namespace std;
class Per
{
    string name;
public://Per中,自己定义了有参构造,系统不再提供无参构造Per(string name){this->name = name;
        cout << "Per的有参构造" << endl;}~Per(){
        cout << "Per的析构函数" << endl;}
};class Stu
{int age;float high;int score;//Per p1;   //Per类只有有参构造函数
public:Stu(){
        cout << "Stu的无参构造函数" << endl;}//构造函数支持函数重载Stu(int age,float high){this->age = age;this->high = high;
        cout << "Stu的有参构造" << endl;}//拷贝构造Stu(Stu &other){//this->age = other.age;this->high = other.high;
        cout << "拷贝构造函数" << endl;}~Stu(){
        cout << "Stu的析构函数" << endl;}void show();
};
void Stu::show()
{
    cout << "age = " << age << endl;
    cout << "high = " << high << endl;
}
int main()
{
    Stu s1(19,100);
    cout << "s1的show:" << endl;
    s1.show();
    Stu s2=s1;
    cout << "s2的show:" << endl;
    s2.show();return 0;
}

iii)深浅拷贝问题**

当类中有指针成员,会涉及到深浅拷贝问题

浅拷贝:两个不同类对象的指针成员,指向同一片空间

问题:析构时,会发生二次释放问题;同一片空间被两个不同的类对象占用,发生资源抢占

深拷贝:两个不同类对象的指针成员,指向不同的空间,但是保存的是同样的数据

浅拷贝

深拷贝

#include <iostream>using namespace std;
class Stu
{
    string name;int *p;
public:Stu():p(new int)   //保证指针成员,指向堆区的空间{
        cout << "堆区申请的空间为:" << p << endl;
        cout << "Stu的无参构造" << endl;}Stu(string name,int p):name(name),p(new int(p)){}~Stu(){
        cout << "准备释放堆区的空间:" << p << endl;delete p;        cout << "Stu的析构函数" << endl;}//使用同类其他对象的指针成员解引用后的值,给自己的指针成员的内容初始化Stu(Stu &other):name(other.name),p(new int(*(other.p))){/*this->name = other.name;
        this->p = new int(*(other.p));*/
        cout << "Stu的拷贝构造" << endl;}void show();
};
void Stu::show()
{
    cout << "name= " << name << endl;
    cout << "p= " << p << endl;
    cout << "*p= " << *<< endl;
}
int main()
{
    Stu s1("zhangsan",18);
    cout << "s1的show:" << endl;
    s1.show();
    Stu s2 = s1;
    cout << "s2的show:" << endl;
    s2.show();return 0;
}

iv)拷贝构造函数的调用时机

  1. 使用已有的类对象,给新的类对象初始化
  2. 函数的参数是一个类对象时,也会调用拷贝构造函数
  3. 函数的返回值是一个类对象时,也会调用拷贝构造函数

测试代码:

#include <iostream>using namespace std;
class Stu
{
    string name;
public:Stu(){
        cout << "Stu的无参构造" << endl;}Stu(Stu &other):name(other.name){
        cout << "Stu的拷贝构造函数" << endl;}Stu(string name):name(name){
        cout << "Stu的右参构造" << endl;}
};Stu fun(Stu s1)
{return s1;
}
int main()
{
    Stu s;//Stu s2(fun(s));   //会报错,因为fun(s)的返回值是一个临时值,不能引用return 0;
}

【8】拷贝赋值函数 

使用已有的类对象,给另外一个已有的类对象赋值

系统默认提供一个拷贝赋值函数

本质:赋值运算符的重载

i)格式

类名 &operator=(const 类名&other)
{
  //函数体
}

ii)代码

 #include <iostream>using namespace std;
class Stu
{
    string name;int *p;
public://深拷贝赋值函数
    Stu &operator=(const Stu &other){
        name = other.name;*= *(other.p);
        cout << "Stu的拷贝赋值函数" << endl;return *this;}Stu():p(new int)   //保证指针成员,指向堆区的空间{
        cout << "堆区申请的空间为:" << p << endl;
        cout << "Stu的无参构造" << endl;}Stu(string name,int p):name(name),p(new int(p)){}~Stu(){
        cout << "准备释放堆区的空间:" << p << endl;delete p;        cout << "Stu的析构函数" << endl;}//使用同类其他对象的指针成员解引用后的值,给自己的指针成员的内容初始化Stu(Stu &other):name(other.name),p(new int(*(other.p))){/*this->name = other.name;
        this->p = new int(*(other.p));*/
        cout << "Stu的拷贝构造" << endl;}void show();
};
void Stu::show()
{
    cout << "name= " << name << endl;
    cout << "p= " << p << endl;
    cout << "*p= " << *<< endl;
}
int main()
{
    Stu s1("zhangsan",18);
    cout << "s1的show:" << endl;
    s1.show();
    Stu s2;
    s2 = s1;
    cout << "s2的show:" << endl;
    s2.show();return 0;
}

【9】匿名对象

没有对象名,通过类名实例化出来的对象,类名();

Stu();生命周期更短

  1. 全局函数传参
  2. 类数组赋值     //int a=9,b=7,c=8;    int arr[3]={a,b,c};   //int arr[3]={9,7,8};
  3. 临时调用类中的成员函数
  4. 给新的类对象赋值
#include <iostream>using namespace std;
class Stu
{
    string name;int *p;
public://深拷贝赋值函数
    Stu &operator=(const Stu &other){
        name = other.name;*= *(other.p);
        cout << "Stu的拷贝赋值函数" << endl;return *this;}Stu():p(new int)   //保证指针成员,指向堆区的空间{
        cout << "堆区申请的空间为:" << p << endl;
        cout << "Stu的无参构造" << endl;}Stu(string name,int p):name(name),p(new int(p)){}~Stu(){
        cout << "准备释放堆区的空间:" << p << endl;delete p;        cout << "Stu的析构函数" << endl;}//使用同类其他对象的指针成员解引用后的值,给自己的指针成员的内容初始化Stu(const Stu &other):name(other.name),p(new int(*(other.p))){/*this->name = other.name;
        this->p = new int(*(other.p));*/
        cout << "Stu的拷贝构造" << endl;}void show();
};
void Stu::show()
{
    cout << "name= " << name << endl;
    cout << "p= " << p << endl;
    cout << "*p= " << *<< endl;
}void fun(Stu s1)
{
    cout << "调用成功" << endl;
}
int main()
{//1、使用匿名对象用做全局函数传参fun(Stu());   //匿名对象的生命周期,只在定义语句的位置,是一个临时值//2、想要临时使用类中的成员函数Stu().show();//3、给类对象的数组赋值
    Stu arr[3]={Stu("zhangsan",8),Stu("lisi",19),Stu("xiaoming",20)};//4、给新的类对象赋值
    Stu s3(Stu("zhangsan",18));return 0;
}

【10】C++中结构体和C的区别以及C++中结构体和类的区别

  1. C中定义需要加struct,C++中可以不加struct
  2. C++中结构体可以有访问权限的控制(public、private、protected)
  3. C++中结构体可以继承
  4. C++中结构体可以封装函数
  5. C++中结构体内可以定义另外一个结构体声明(类型)

结构体和类的区别:

  1. 使用场合不同,类适用于某一类对象属性和方法的封装,结构体用于某种数据结构的实现
  2. 类中默认private,结构体中默认是public
  3. 类默认是私有继承,结构体默认是共有继承
  4. 类的封装性比结构体的封装性更好

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

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

相关文章

【AIGC大模型】跑通wonder3D (windows)

论文链接&#xff1a;https://arxiv.org/pdf/2310.15008.pdf windows10系统 显卡&#xff1a;NVIDIA rtx 2060 一、安装anaconda 二、安装CUDA 11.7 (CUDA Toolkit 11.7 Downloads | NVIDIA Developer) 和 cudnn 8.9.7(cuDNN Archive | NVIDIA Developer)库 CUDA选择自定…

Mysql数据库学习之范式

范式 范式简介 在关系型数据库中&#xff0c;关于数据表设计的基本原则、规则称为范式。可以理解为&#xff0c;一张数据表的设计结构需要满足的某种设计标准的级别&#xff0c;要想设计一个结构合理的关系型数据库&#xff0c;必须满足一定的范式。 范式都包含哪些 6种范式…

matlab|计及源荷不确定性的综合能源生产单元运行调度与容量配置随机优化模型

目录 1 主要内容 1.1 风光场景聚类 1.2 主模型程序结果 1.3 随机模型和确定性模型对比 1.4 有无储气对比 1.5 煤价灵敏性分析 1.6 甲烷价格灵敏性分析 2 部分程序 3 下载链接 1 主要内容 本程序复现《计及源荷不确定性的综合能源生产单元运行调度与容量配置两阶段随机…

300分钟吃透分布式缓存-14讲:大数据时代,MC如何应对新的常见问题?

大数据时代 Memcached 经典问题 随着互联网的快速发展和普及&#xff0c;人类进入了大数据时代。在大数据时代&#xff0c;移动设备全面融入了人们的工作和生活&#xff0c;各种数据以前所未有的 速度被生产、挖掘和消费。移动互联网系统也不断演进和发展&#xff0c;存储、计…

【前沿热点视觉算法】-钢缺陷图像显著目标检测的跨尺度边缘净化网络

计算机视觉算法分享。问题或建议&#xff0c;请文章私信或者文章末尾扫码加微信留言。 1 论文题目 钢缺陷图像显著目标检测的跨尺度边缘净化网络 2 论文摘要 显著目标检测在自然场景图像中取得了很大的成功&#xff0c;但在钢缺陷图像&#xff08;SDIs&#xff09;中仍有很大…

【C语言】linux内核ipoib模块 - ipoib_tx_poll

一、中文注释 这段代码是 Linux 内核网络栈中与 InfiniBand 协议相关的一个部分&#xff0c;特别是与 IP over InfiniBand (IPoIB)相关。该函数负责去处理IPoIB的发送完成队列&#xff08;发送CQ&#xff09;上的工作请求&#xff08;work completions&#xff09;。以下是对这…

802.11局域网的 MAC 层协议、CSMA/CA

目录 802.11 局域网的 MAC 层协议 1 CSMA/CA 协议 无线局域网不能使用 CSMA/CD 无线局域网可以使用 CSMA 协议 802.11 的 MAC 层 分布协调功能 DCF 点协调功能 PCF CSMA/CA 协议的要点 2 时间间隔 DIFS 的重要性 SIFS DIFS 3 争用信道的过程 时隙长度的确定 退避…

【FPGA】线性反馈移位寄存器(LFSR)的Verilog实现

什么是移位寄存器 移位寄存器&#xff1a;是指多个寄存器并排相连&#xff0c;前一个寄存器的输出作为下一个寄存器的输入&#xff0c;寄存器中存放的数据在每个时钟周期向左或向右移动一位。 下面的右移移位寄存器因为左侧没有有效输入&#xff0c;所以在第4个时钟周期&…

【JavaEE】_HttpServlet类

目录 1. init方法 2. destory方法 3. service方法 4. servlet生命周期 前文已经提及到&#xff1a;servlet是tomcat提供的&#xff0c;用于操作HTTP协议的一组API&#xff0c;可以将这组API理解为HTTP服务器的框架&#xff1b; 编写一个servlet程序&#xff0c;往往都要继…

element table数据量太大,造成浏览器崩溃。解决方案

这是渲染出来的数据 其实解决思路大致就是&#xff1a;把后台返回的上万条数据&#xff0c;进行分割&#xff08;前端分页&#xff09;&#xff0c;这样先加载几十条&#xff0c;然后再用懒加载的方式去concat&#xff0c;完美解决 上代码 <template><div class&quo…

c语言经典测试题6

1.题1 void print(char* s) {if (*s){print(s);printf("%c", *s);} } #include<stdio.h> int main() {char str[] "Geneius";print(str);return 0; } 上述代码是一个递归&#xff0c;那么它运行的结果是什么呢&#xff1f; 我们来分析一下&#x…

跨区域复制建筑UI输入框脚本迷你世界

--复制区域文件 --设置坐标起点&#xff0c;终点 --创建区域 --获取坐标id,data --星空露珠工作室制作 local pos1{x-16,y7,z28} local pos2{x28,y44,z-9} local block{num0} local str{} local str0{} local num0 local count0 local ui6 --几个输入框 local romath.random(…

探索创意的无尽宇宙——Photoshop 2020,你的视觉魔法棒

在数字艺术的广阔天地中&#xff0c;Photoshop 2020无疑是一颗璀璨的明星。这款由Adobe公司精心打造的图像处理软件&#xff0c;自推出以来&#xff0c;便以其强大的功能和卓越的性能&#xff0c;赢得了全球数百万设计师、摄影师和爱好者的青睐。无论是Mac还是Windows系统&…

K8S安装部署

常见的K8S安装部署方式 Minikube Minikube是一个工具&#xff0c;可以在本地快速运行一个单节点微型K8S&#xff0c;仅用于学习、预览K8S的一些特性使用。 部署地址&#xff1a;Install Tools | Kubernetes Kubeadm Kubeadm也是一个工具&#xff0c;提供kubeadm init和kube…

k8s部署 多master节点负载均衡以及集群高可用

一、k8s 添加多master节点实验 1、master02节点初始化操作 2、在master01节点基础上&#xff0c;完成master02节点部署 ①从master01节点复制所需要的文件 需要从master01节点复制etcd数据库所需要的ssl证书、kubernetes安装目录&#xff08;二进制文件、组件与apiserver通信…

海外KOL合作指南:如何专业询价并成功建立合作关系?

近几年&#xff0c;随着社交媒体的迅速发展&#xff0c;与海外KOL合作已成为许多企业推广业务的有效手段。海外KOL具有庞大的粉丝基础和广泛的影响力&#xff0c;与他们合作可以帮助企业扩大品牌知名度、提高产品销售等方面取得显著成果。然而&#xff0c;如何向海外KOL询价&am…

设计模式学习笔记 - 面向对象 - 8.实践:贫血模型和充血模型的原理及实践

1.Web开发常用的贫血MVC架构违背OOP吗&#xff1f; 前面我们依据讲过了面向对象四大特性、接口和抽象类、面向对象和面向过程编程风格&#xff0c;基于接口而非实现编程和多用组合少用继承设计思想。接下来&#xff0c;通过实战来学习如何将这些理论应用到实际的开发中。 大部…

自动化部署证书 acme.sh 使用教程

简介 acme.sh 是一个开源的 ACME 协议的客户端工具&#xff0c;用于自动化申请、更新和部署 SSL/TLS 证书。通过使用 acme.sh&#xff0c;用户可以轻松地在服务器上设置 HTTPS 加密连接&#xff0c;而无需手动操作。它支持多种 DNS 接口和证书颁发机构&#xff0c;可以与各种 …

U盘拒绝访问?快速恢复数据的实用方案!

当您尝试访问U盘时&#xff0c;突然遇到“U盘拒绝访问”的提示&#xff0c;这无疑是一个令人头疼的问题。这不仅意味着您无法读取或写入U盘中的数据&#xff0c;还可能意味着重要文件的安全受到威胁。本文将深入探讨U盘拒绝访问的原因&#xff0c;并为您提供至少两种实用的数据…

electron+vue3全家桶+vite项目搭建【27】封装窗口工具类【1】雏形

文章目录 引入思路抽出公共声明文件抽出全局通用数据类型和方法主进程模块1.抽离基础常量2.封装窗口工具类 渲染进程模块测试结果 引入 demo项目地址 可以看到我们之前在主进程中的逻辑全部都塞到index.ts文件中&#xff0c;包括窗口的一些事件处理&#xff0c;handle监听&am…