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

news2024/11/16 7:40:55

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

【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.coloradmin.cn/o/1468799.html

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

相关文章

Matlab: Introduction to Hybrid Beamforming

文章目录 来源混合波束赋形的基本概念System Setup 来源 在matlab的命令行输入 doc hybrid beamforming 混合波束赋形的基本概念 混合波束形成简介 本例介绍了混合波束形成的基本概念&#xff0c;并说明了如何模拟这种系统。 现代无线通信系统使用空间复用来提高散射体丰富…

创建者模式(Builder Pattern):构造复杂对象的通用解决方案

文章目录 **一、技术背景与应用场景****为何使用创建者模式&#xff1f;****典型应用场景包括但不限于&#xff1a;** **二、创建者模式定义与结构****三、使用步骤举例**四、优缺点分析总结 一、技术背景与应用场景 创建者模式是一种对象创建型设计模式&#xff0c;它通过将复…

代码随想录算法训练营29期|day60 任务以及具体安排

第九章 动态规划part17 647. 回文子串 class Solution {public int countSubstrings(String s) {char[] chars s.toCharArray();int len chars.length;boolean[][] dp new boolean[len][len];int result 0;for (int i len - 1; i > 0; i--) {for (int j i; j < le…

高级语言期末2011级A卷

1.编写函数&#xff0c;判定正整数m和n&#xff08;均至少为2&#xff09;是否满足&#xff1a;数m为数n可分解的最小质因数&#xff08;数n可分解的最小质因数为整除n的最小质数&#xff09; 提示&#xff1a;判定m为质数且m是n的最小因数 #include <stdio.h> #include…

算法打卡day1|数组篇|Leetcode 704.二分查找、27.移除元素

数组理论基础 数组是存放在连续内存空间上的相同类型数据的集合&#xff0c;可以方便的通过下标索引的方式获取到下标下对应的数据。 1.数组下标都是从0开始的。 2.数组内存空间的地址是连续的。 正是因为数组的在内存空间的地址是连续的&#xff0c;所以我们在删除或者增添…

Visual Studio 打开.edmx文件不显示表并报错:没有可用于.edmx的编辑器

打开.edmx文件时&#xff0c;呈现的是xml视图&#xff0c;不显示Diagram视图&#xff0c;且弹出报错“没有可用于.edmx的编辑器” 解决方案&#xff1a;在.edmx文件上右键&#xff0c;选择ado.net entity data model designer&#xff0c;即可正常显示表

mysql-MVCC

一、基础概念 1. MVCC的含义 MVCC (Multiversion Concurrency Control)&#xff0c;即多版本并发控制技术&#xff0c;它是通过读取某个时间点的快照数据&#xff0c; 来降低并发事务冲突而引起的锁等待&#xff0c; 从而提高并发性能的一种机制. MVCC 的实现,是通过保存数据…

N种方法解决1(CTF)

这里遇到的问题&#xff1a;一开始采用的base64解码平台有问题&#xff1b;默认解密出的格式为GBK格式&#xff1b;直接复制粘贴发现无法还原图片&#xff1b;又尝试了其他编码的&#xff1b;发现只有hex格式可以保证图片正常还原&#xff1b; 图片是以二进制存储的&#xff1…

响应式页面兼容移动端

文章目录 1. 响应式开发1.1 原理1.2 响应式容器 2. Bootstrap前端开发框架2.1 Bootstrap介绍(1) 优点(2) 版本 2.2 Bootstrap使用2.3 布局容器(1) container类(2) container-fluid类 3.Bootstrap栅格系统3.1 介绍3.2 栅格选项参数3.3 列嵌套3.4 列偏移3.5 列排序3.6 响应式工具…

Android14之input高级调试技巧(一百八十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【Python笔记-设计模式】享元模式

一、说明 享元模式是一种结构型设计模式&#xff0c;它摒弃了在每个对象中保存所有数据的方式&#xff0c;通过共享多个对象所共有的相同状态&#xff0c;让你能在有限的内存容量中载入更多对象。 (一) 解决问题 旨在减少大量相似对象创建时的内存开销 (二) 使用场景 大量…

C++的STL常用算法->常用遍历算法、常用查找算法、常用排序算法、常用拷贝和替换算法、常用算术生成算法、常用集合算法

#include<iostream> using namespace std; #include <algorithm> #include <vector> //常用遍历算法 for_each //普通函数 void print01(int val) { cout << val << " "; } //仿函数 //函数对象 class print02 { public: v…

第 2 章 ROS通信机制_通信机制实操(自学二刷笔记)

重要参考&#xff1a; 课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ 讲义链接:Introduction Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 2.5.1 实操01_话题发布 需求描述&#xff1a;编码实现乌龟运动控制&#xff0c;让小乌龟做圆周运动。 结果演…

前端工程化面试题 | 16.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

微信小程序 uniapp+vue餐厅美食就餐推荐系统

本论文根据系统的开发流程以及一般论文的结构分为三个部分&#xff0c;第一个部分为摘要、外文翻译、目录&#xff1b;第二个部分为正文&#xff1b;第三个部分为致谢和参考文献。其中正文部分包括&#xff1a; &#xff08;1&#xff09;绪论&#xff0c;对课题背景、意义、目…

nodejs:nrm(npm的镜像源管理器)

nrm&#xff08;Npm Registry Manager&#xff09;是一个用于快速切换和管理Node.js包管理器npm的镜像源&#xff08;registry&#xff09;的工具。 通过nrm&#xff0c;开发者可以轻松查看当前使用的npm源、添加新的镜像源、测试不同镜像源的速度&#xff0c;并在多个镜像源之…

pdffactory pro 8中文破解版

详细介绍 PdfFactory&#xff0c;PDF文档虚拟打印机&#xff0c;无须Acrobat即可创建Adobe PDF文件&#xff0c;创建PDF文件的方法比其他方法更方便和高效。支持将多个文档整合到一个PDF文件、增加字体和便签、PDF加密、去水印、压缩优化。 FinePrint&#xff0c;Windows虚拟…

mysql json数据模糊查询

场景&#xff1a;当一个列是json字符串时&#xff0c;想模糊查询json字符串中某个字段。 mysql5.7版本已经有了json数据类型&#xff0c;并且有了处理json数据类型的函数。具体看下面的文档地址。这里只说当需要对json中某个字段模糊查询时该怎么写。可以直接用 like的模糊查询…

【DDD】学习笔记-领域模型与数据模型

领域模型与数据模型 领域驱动的设计模型最重要的概念就是聚合&#xff0c;同时&#xff0c;聚合还要受到限界上下文边界的控制。Eric Evans 之所以要引入限界上下文&#xff0c;其中一个重要原因就是因为我们“无法维护一个涵盖整个企业的统一模型”&#xff0c;于是需要限界上…

!!!Python虚拟环境改名后的坑!!!!

搞了一晚上终于弄好这python虚拟环境的问题了&#xff01;真的是坑啊&#xff01; 本来用的纯python环境下的虚拟环境&#xff0c;一时心血来潮&#xff0c;把电脑重新装了一遍&#xff0c;虚拟环境的目录也改了一下&#xff0c;结果虚拟环境再vscode中是可以使用&#xff0c;…