C++笔记:类和对象

类和对象

        认识类和对象

         先来回忆一下C语言中的类型和变量,类型就像是定义了数据的规则,而变量则是根据这些规则来实际存储数据的容器。类是我们自己定义的一种数据类型,而对象则是这种数据类型的一个具体实例。类就可以理解为类型,而对象就可以理解为变量,而且对象是更加高级的变量。

        类型 = 类型数据 + 类型操作

        比如double类型

        他的数据类型占用8字节,并且可以表示成小数。

        类型操作可以加减乘除,但是它不支持模(%)运算。

        那么类就是包含了类型数据和类型操作的一个集合。

        也可以理解为数据就是类的属性,操作就是类的行为

        通过下面我定义的一个人的类,那么height,sex, age都是这个类的类型数据,而类型操作就是函数run和函数speak。

class People {
    double height;//身高
    char sex;//性别
    int age;//年龄
    string name;//姓名
    void run() {//跑
        cout << "I can run" << endl;
    }
    void speak() {//说话
        cout << "I can speak" << endl;
    }
};

        那么我需要一个特定的人的时候,我就需要定义一个对象用来存这个特定人的属性。

        下面的用类定义一个对象,并且对他的属性进行赋值。

People a;
a.name = "Zhang san";
a.age = 18;
a.sex = '1';//女0,男1
a.height = 1.89;

        而我需要这个人进行说话或者跑时,就需要调用他相应的操作,也就是函数。

a.run();
a.speak();

        访问权限

        public:是公共的资源,是谁都可以访问的资源,比如空气,阳光,公共场合都是谁都可以访问进行使用的。

        private:是私有的资源,是只能类自己进行访问的资源,比如每个人自己的私人物品,是只能自己使用和访问的。

        protected:是受保护的资源,是只能自己访问以及自己的子类访问的资源,比如你儿子可以使用你的东西。(在后续文章继承时会用到protected权限)

        friendly:是在关键字friend声明后,它允许被声明后的类或函数访问这一个类的私有或受保护的资源,比如你的好兄弟在你的允许下可以访问和使用你的私人物品。(在后续的文章中会更新到使用)

        重点:这里的访问权限是规定的类外对该类类内的访问权限。

        比如我在一个类中定义了一个访问权限为私有的方法,那么我只能在这个类的内部进行调用,在类外是无法调用的,除非我对这个方向进行了friend友元声明。

        对于为什么要为什么要有访问权限的设置,看如下代码:

#include<iostream>
using namespace std;


class People {
public :
int age;
    void speak() {
        cout << "my age is "<< age << endl;
        return ;
    }
};


int main() {
    People a;
    a.age = -100;
    a.speak();
    return 0;
}

        如果对于age是public公有访问的,那么在设置年龄的将不会受到限制,对于这份代码可能没有问题,如果在以后设计项目或者工程时,就会造成灾难性的错误。

        那么正确的写法应该如下,把age设置为私有的,对age赋值时,定义一个函数来进行对age赋值,并判断值是否在正确范围内,对于获取age值也定义一个函数进行来获取。

#include<iostream>
using namespace std;


class People {
public :
    void speak() {
        cout << "my age is "<< age << endl;
        return ;
    }
    void set_age(int x) {
        if (age <= 0 || age > 1000) {
            perror("your age is error\n");
            exit(1);
        }
        age = x;
        return ;
    }
    int get_age() {
        return age;
    }
private :
    int age;
};


int main() {
    People a;
    a.set_age(-100);
    a.speak();
    return 0;
}

构造函数和析构函数

        定义一个对象的流程:

     对于构造函数的详细解析如下代码:

#include<iostream>
using namespace std;

class A {
public :
    A() {//默认构造函数
        cout << "default constructor" << endl;
    }
    //如果这里没有const关键字,传入的对象是const声明的那么就会报错
    //如果没有&(引用),那么将会造成无限套娃的拷贝构造
    //假如这里没有&,那么这里的形参就相当于实参给他赋值
    //而赋值就是 A a = b, b是实参传入的值
    //那这里就会又调用构造函数,形成无限套娃
    A(const A &a) {
        this->x = a.x;
        this->y = a.y;
        cout << "copy constructor" << endl;
    }
    A(int x, int y) {//有参构造函数
        cout << "have parameter constructor" << endl;
        this->x = x;//this表示当前对象的地址
        this->y = y;
    }
    void operator=(const A &a) {//这个函数是=运算符重载,是类中默认有的
        cout << "this is assigment"  << endl;
        return ;
    }
    A(int x) {//转换构造函数
        cout << "conversion constructor" << endl;
        this->x = x;
        this->y = 0;
    }
    void output() {
        cout << "(" << x << ", " << y << ")" << endl;
    }
    ~A() {//析构函数
        cout << "destructor" << endl;
    }
private :
    int x, y;
};


void func(A a) {
    cout << "func : ";
    a.output();
    return ;
}


int main() {
    A a;//调用默认构造函数
    cout << "1-------------------------" << endl;
    A b(1, 2);//调用有参构造
    cout << "2-------------------------" << endl;
    //这里就调用了拷贝构造函数
    A e = b;
    cout << "3-------------------------" << endl;
    //这里只是运用了普通赋值运算符
    //通过执行会发现没有执行任何构造函数
    a = b;
    cout << "4-------------------------" << endl;
    //调用转换构造,将int类型转换为A类型
    //这里也可以是另一个类型的对象,那也是转换构造
    //不过还需要从新定义一个需要转换构造的函数,里面的参数就是对应的类型
    A c(3);
    cout << "5-------------------------" << endl;
    //这里调用的是拷贝构造函数,将对象b进行拷贝给函数形参a
    func(b);
    func(c);
    cout << "6-------------------------" << endl;
    //对于这中函数调用情况
    //这里就会用到转换构造
    //他会隐式的将int类型5通过转换构造转会为A类型
    func(5);
    cout << "7-------------------------" << endl;
    //这里相当于A d(4);
    //这里可以这样理解
    //等号类型相同编程才能通过
    //那么4,int类型就会通过转换构造变成A类型
    //如果没有转换构造那么就编译无法通过
    A d = 4;
    a = 6;
    cout << "8-------------------------" << endl;
    return 0;
}

构造函数的初始化列表

构造函数中的初始列表使用:

#include<iostream>
using namespace std;

class C {
public:
    C(int n) {
        this->num = n;
        cout << "C coversion constructor" << endl;
    }
    void output() {
        cout << num;
    }
private :
    int num;
};

class A {
public :
    //:后面是构造函数的初始化列表
    A(int a) : a(a), b(10), c(6) {
        cout << "A constructor" << endl;
    }
    void output() {
        cout << " " <<a << " " << b << " ";
        c.output();
        cout << endl;
        return ;
    }
private :
    int a, b;
    C c;
};


int main() {
    A a(2);
    a.output();
    return 0;
}

构造函数和析构函数的调用顺序

如下这份代码:

#include <iostream>
#include <string>
using namespace std;


class A {
public :
    A() {};
    A(string n)  {
        name = n;
        cout << name << " class A construtor" << endl;
    }
    ~A() {
        cout << name << " class A destructor" << endl;
    }
int *p;
private :
    string name;
};

class B {
public :
    //:a(a)
    //:后面是构造函数时,最该对象中的成员属性进行初始化操作
    B(string n, A &a) : a(a){
        name = n;
        cout << name << " class B construtor" << endl;
        //new关键字可以理解为,C语言中malloc去堆区中开辟一段空间
        a.p = new int[10];
        return ;
    }
    A &a;//创建一个引用属性,这里&a可以暂时理解为取a的地址
    ~B() {
        //delete就相当于C语言中的free对开辟空间的释放
        delete a.p;
        cout << name << " class B destructor" << endl;
    }
private :
    string name;
};


int main() {
    A a("a");
    B b("b", a);
    return 0;
}

执行结果:

        可以发现,析构顺序是构造顺序反过来的,通过代码可以发现在B中的有参构造中用到了a对象的引用,然后对a对象的p指针开辟了一段空间,如果析构时顺序和构造顺序一样的那么,在析构b对象时,去delete a.p去释放开辟的空间时,a对象已经被析构掉了,那就也无法去找a对象中的指针p了。

        

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

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

相关文章

配置优先级标记和队列调度示例

配置优先级标记和队列调度示例 组网图形 图1 优先级标记和队列调度示例组网图 优先级标记和队列调度简介配置注意事项组网需求配置思路操作步骤配置文件 优先级标记和队列调度简介 报文进入设备之后&#xff0c;设备会根据相应的规则分配或修改报文各种优先级的值&#xff…

【鸿蒙开发】饿了么页面练习

0. 整体结构 整体划分3部分。店铺部分&#xff0c;购物车部分&#xff0c;金额统计部分。使用 Stack 把3部分堆叠 0.1 整体页面 Index.ets 修改 Index.ets &#xff0c;使用堆叠布局&#xff0c;并居底部对齐 import { ElShop } from ../components/ElShop import { ElShopp…

slRegisterDistribution failed with error: 0x8000000d Error: 0x8000000d ?

powershell用管理员打开&#xff0c;输入Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux 怎么用管理员权限打开powershell&#xff1f;

告别传统开发,轻松套用模板,低代码平台助你快速构建商城与网站

随着人工智能时代的到来&#xff0c;很多复杂的工作再日益变得简单。比如20年前开发一个在线商城完成支付交易&#xff0c;那是一个不得了的事情&#xff0c;现在的零售巨头淘宝和京东就是在那个时代崛起的。新时代涌现出了许多新的工具&#xff0c;比如使用低代码平台搭建的自…

【STL详解 —— priority_queue的使用与模拟实现】

STL详解 —— priority_queue的使用与模拟实现 priority_queue的使用priority_queue的介绍priority_queue的定义方式priority_queue各个接口的使用 priority_queue的模拟实现仿函数priority_queue的模拟实现 priority_queue的使用 priority_queue的介绍 std::priority_queue 是…

排序1——C语言

排序 1. 复杂度2. 插入排序2.1 直接插入排序2.2 希尔排序 3. 选择排序3.1 直接选择排序3.2 堆排序 排序在生活中很常见&#xff0c;比如在网购时&#xff0c;按价格排序&#xff0c;按好评数排序&#xff0c;点餐时&#xff0c;按评分排序等等。而排序有快和慢&#xff0c;快的…

IIC和OLED再认识

IIC介绍 51是由于芯片功能不齐全&#xff0c;以至于需要软件编写IIC 而STM32芯片足够将IIC配置在硬件当中以至于直接读写即可 忘记了可回顾51的16.IIC 协议 和 OLED_oled,iic通信波特率-CSDN博客 在STM32中使用IIC可以直接调用HAL库的库函数&#xff1a; HAL_StatusTypeDe…

Appium Desktop + Appium Inspector + 模拟器连接

一、环境预备 1.你需要安装好配置好adb,确保可以在命令行直接运行adb指令 2.安装Appium Desktop、Appium Inspector 、 模拟器 二、启动appium 服务 启动后&#xff0c;画面如下&#xff1a; 三、启动模拟器 此时&#xff0c;启动模拟器&#xff0c;打开电脑cmd窗口&#x…

研发岗-统信UOS系统配置npm git等前端常用配置

第一步 获取root权限 配置环境等都需要用到root权限&#xff0c;所以我们先获取到root权限&#xff0c;方便下面的操作 下载软件 在UOS应用商店下载的所需应用 版本都比较低 安装node 官网下载了【arm64】的包&#xff0c;解压到指定文件夹&#xff0c;设置链接&#xff0…

揭秘AI精准输出:如何构建完美的AIGC提示词?

揭秘AI精准输出&#xff1a;如何构建完美的AIGC提示词&#xff1f;&#x1f916; 文章目录 揭秘AI精准输出&#xff1a;如何构建完美的AIGC提示词&#xff1f;&#x1f916;摘要引言正文&#x1f4d8; 提示词的基本概念1. 什么是提示词&#xff1f;2. 提示词的作用 &#x1f4d…

JAVA云HIS与LIS想知道区别在哪里吗?一分钟带你快速了解

JAVA云HIS与LIS想知道区别在哪里吗&#xff1f;一分钟带你快速了解 HIS系统与LIS系统使用各自独立的服务器&#xff0c;数据库不同&#xff0c;HIS系统、LIS系统服务器分别使用ORACLE数据库和SQLSERVER数据库&#xff0c;彼此数据信息不能共真&#xff0c;要解决HIS系统与LIS系…

vue iview table实现全选

之前我们在文章《iview Table实现跨页勾选记忆功能以及利用ES6的Map数据结构实现根据id进行对象数组的去重》里实现过全选功能,不过那有一个弊端就是需要调接口一次性获取全部的数据,这会造成请求数据响应超时或报错,因为数据量大的话这样体验也不好,于是我们改了一下,因为…

aosp13/14命令行进入分屏相关实战

背景&#xff1a; 分屏一般在手机上都是都是从桌面的最近任务卡片进入的&#xff0c;一般来说手机用户都是这样操作的&#xff0c;但是有一些场景或者情况就不一定可以顺利用上这个桌面的多任务卡片进入。 比如以下场景&#xff1a; 1、可能不是桌面的多任务的场景&#xff0c…

【Altium Designer 20 笔记】PCB铺铜过程

PCB铺铜步骤 切换到Keep-Out Layer&#xff08;禁止布线层&#xff09; 使用shifts键切换单层显示 画禁止布线范围&#xff08;防止铺铜过大&#xff09; 切换到需要铺铜的层 选择铺铜网络&#xff0c;通常是地&#xff08;GND&#xff09;或某个电源网络 隐藏覆铜&#xff1a;…

一.吊打面试官系列-数据库优化-认识MySql索引

1.什么是索引 索引&#xff08;Index&#xff09;是帮助DBMS&#xff08;数据库&#xff09;高效获取数据的数据结构&#xff0c;索引是为了加速对表中数据行的检索而创建的一种分散的存储结构。如果数据库没有索引就会走表进行全表扫描&#xff0c;一旦数据量上来&#xff0c…

如何基于香橙派AIpro对视频/图像数据进行预处理

背景介绍 受网络结构和训练方式等因素的影响&#xff0c;绝大多数神经网络模型对输入数据都有格式上的限制。在计算机视觉领域&#xff0c;这个限制大多体现在图像的尺寸、色域、归一化参数等。如果源图或视频的尺寸、格式等与网络模型的要求不一致时&#xff0c;我们需要对其…

【中间件】ElasticSearch简介和基本操作

一、简介 Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎&#xff0c;支持各种数据类型&#xff0c;包括文本、数字、地理、结构化、非结构化 ,可以让你存储所有类型的数据&#xff0c;能够解决不断涌现出的各种用例。其构成如下&#xff1a; 说明&#xff1…

递归、搜索与回溯算法——递归

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享递归,搜索与回溯算法关于递归的专题 如果有不足的或者错误的请您指出! 目录 1.什么时候使用递归2.汉诺塔2.1解析2.2题解 3.合并两个有序链表3.1解析3.2题解 4.翻转链表4.1解析4…

Spring Boot 统一功能处理(二)

本篇主要介绍Spring Boot统一功能处理中的统一数据返回格式。 目录 一、定义统一的返回类 二、配置统一数据格式 三、测试配置效果 四、统一格式返回的优点 五、源码角度解析String问题 一、定义统一的返回类 在我们的接口在处理请求时&#xff0c;返回的结果可以说是参…

判断位数、按位输出、倒序输出(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int number 0;int i 1;int m 0;int z 0;int z1 0, z2 0, z3 0, z4 0;//提示用户&#xff1b;printf("请输…
最新文章