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. 类的封装性比结构体的封装性更好

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

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

相关文章

运维的利器–监控–zabbix–grafana

运维的利器–监控–zabbix–grafana 一、介绍 Grafana 是一个跨平台的开源的度量分析和可视化工具 , 可以通过将采集的数据查询然后可视化的展示 。zabbix可以作为数据源&#xff0c;为grafana提供数据&#xff0c;然后grafana将数据以图表或者其他形式展示出来。zabbix和gra…

AI:142-开发一种智能家居系统,通过语音识别和情感分析实现智能互动

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带关键代码,详细讲解供大家学习,希望…

【c++】 STL的组件简介与容器的使用时机

STL六大组件简介 STL提供了六大组件&#xff0c;彼此之间可以组合套用&#xff0c;这六大组件分别是:容器、算法、迭代器、仿函数、适配器&#xff08;配接器&#xff09;、空间配置器。 容器&#xff1a;各种数据结构&#xff0c;如vector、list、deque、set、map等,用来存放…

(十八)devops持续集成开发——使用docker安装部署jenkins服务

前言 本节内容介绍如何使用docker容器来部署安装jenkins流水线服务。关于docker容器的安装本节内容不做介绍。请读者提前安装。 正文 ①使用docker查找jenkins官方镜像 ② 拉取jenkins官方镜像jenkins/jenkins&#xff0c;选择一个最新稳定版本&#xff0c;避免一些插件不兼…

AI赚钱套路总结和教程

最近李一舟和Sora 很火&#xff0c;作为第一批使用Sora赚钱的男人&#xff0c;一个清华学美术的跟人讲AI&#xff0c;信的人太多了&#xff0c;钱太好赚了。3年时间&#xff0c;李一舟仅通过卖课就赚了1.75亿元&#xff0c;其中《每个人的人工智能课》收入2786万元&#xff0c;…

2024022601-数据库语言SQL

数据库语言SQL SQL的发展 1974年&#xff0c;由Boyce和Chamberlin提出 1975~1979&#xff0c;IBM San Jose Research Lab的关系数据库管理系统原型System R实施了这种语言 SQL-86是第一个SQL标准 SQL-89、SQL-92(SQL2)、SQL-99(SQL3) 非过程化语言 SQL语言进行数据库操作…

将python两个版本添加环境变量(Mac版)

在运行程序的时候&#xff0c;可能不知道选择哪个版本的程序来执行&#xff0c;先添加环境变量&#xff0c;然后进行选择。 1、查看python安装路径 which python which python3 来查看各个版本的安装位置 2、编辑环境变量配置文件 Macos使用默认终端的shell是bash&#xff0c…

leetcode 2.合并两个有序链表

1..题目&#xff1a;合并两个有序链表&#xff1b; 2.用例&#xff1a; 3.解题思路&#xff1a; &#xff08;1&#xff09;函数头&#xff1a;参数是两个链表&#xff1b;返回值为 链表指针 ListNode*&#xff1b; &#xff08;2&#xff09;函数体&#xff1a; 1.首先比较…

第十四天-redis操作

目录 1.安装 2.创建链接 1.创建链接 2.连接池链接 3.操作指令 1.字符串操作 set/get 2.expire 3.delete 4.mset/mget 5.list列表操作 6.set集合操作&#xff1a; 7.hash的操作 8.事务 1.安装 1. 安装redis-py模块&#xff1a;&#xff1a; pip install redis 2.参…

一文带你了解MySQL之B+树索引的原理

前言 学完前面我们讲解了InnoDB数据页的7个组成部分&#xff0c;知道了各个数据页可以组成一个双向链表&#xff0c;而每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表&#xff0c;每个数据页都会为存储在它里边儿的记录生成一个页目录&#xff0c;在通过主键查…

Java中web的css、js、img等静态资源引入详细操作教程

本篇文章主要讲解&#xff1a;Java中web的css、js、img等静态资源引入详细操作教程 日期&#xff1a;2024年2月27日 作者&#xff1a;任聪聪 java中web单体项目静态资源webjar引入形式说明 说明&#xff1a;通过webjar进行静态资源的导入&#xff0c;使用maven进行版本的管理。…

FPGA IO命名与Bank划分

文章目录 IO的命名IO物理命名IO功能命名 Bank简介FPGA器件功能命名与Bank划分查找XILINXIntelLATTICE IO的命名 IO物理命名 FPGA的IO物理命名规则&#xff0c;也就是我们做管脚约束时候的命名。芯片通常是长方体或者正方体&#xff0c;所以命名通常采用字母数字组合的方式&am…

Jquery中的事件与动画

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 本章目标 使用常用简单事件制作网页特效使用鼠标事件制作主导航特效使用hover()方法制作下拉菜单特效使用鼠标事件及动画制作页面特效 一.Jquery事件概述 二.基础事件 鼠标事件 演示案例&…

pageHelper分页查询

文章目录 前言一、集成1.引入库2.配置yml 二、编码1.Controller2.Service3.Mapper4.Mapper.xml5.StudentResult 三、测试1.根据页码和页数2.根据name 总结 前言 本篇文章介绍在java中使用pageHelper完成分页的功能。 使用的数据库为mysql,持久层框架mybatis。 一、集成 1.引入…

猫头虎分享已解决Bug || RAID阵列故障(RAID Array Failure):RAIDError, DiskArrayFailure

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

Kafka入门二——SpringBoot连接Kafka示例

实现 1.引入maven依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache…

TensorRT及CUDA自学笔记003 NVCC及其命令行参数

TensorRT及CUDA自学笔记003 NVCC及其命令行参数 各位大佬&#xff0c;这是我的自学笔记&#xff0c;如有错误请指正&#xff0c;也欢迎在评论区学习交流&#xff0c;谢谢&#xff01; NVCC是一种编译器&#xff0c;基于一些命令行参数可以将使用PTX或C语言编写的代码编译成可…

Angular升级后运行编译变慢?如何解决?

公司的Angular项目升级后&#xff0c;使用体验感十分不好&#xff0c;运行、编译的时间明显增长&#xff0c;工作效率是十分低下&#xff0c;但奈何公司的大佬们都有自己的事情要忙&#xff0c;结识的大佬也不够多&#xff0c;只能靠自己找度娘了。但是&#xff0c;哎&#xff…

日更【系统架构设计师知识总结2】指令系统(结合真题)

【原创精华】结合老师的讲授、耗费三个小时的精华总结对正在备考的你一定有用&#xff01;&#xff01;自己一点点手打、总结的脑图&#xff0c;把散落在课本以及老师讲授的知识点合并汇总&#xff0c;反复提炼语言&#xff0c;形成知识框架。希望能给同样在学习的伙伴一点帮助…

Python接口自动化之unittest单元测试!

以下主要介绍unittest特性、运行流程及实际案例。 一、单元测试三连问 1、什么是单元测试&#xff1f; 按照阶段来分&#xff0c;一般就是单元测试&#xff0c;集成测试&#xff0c;系统测试&#xff0c;验收测试。单元测试是对单个模块、单个类或者单个函数进行测试。 将访…