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进行拷贝给函数形参afunc(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了。

类属性与方法 

        对于上面的代码的类中,它们只有成员属性和成员方法。

        就拿文章中的第一份代码来看,对于属性,也就是类中的变量,他所存储的值是跟着对象改变而改变的,而类中的两个方法(函数),也是随着对象改变而改变的,因为它们的输出也是不同的。所以这些叫做成员属性和成员方法。

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

 下面这份代码是对成员属性和成员方法的使用:

#include<iostream>
using namespace std;class Point {public :Point() : x(0), y(0) {} //默认构造//区分x和y//在x(x),括号外是成员属性x,括号内是形参xPoint(int x, int y) : x(x), y(y) {} //有参构造void set_x (int x) { this->x = x; }void set_y (int y) { this->y = y; }int get_x() { //访问类中的类属性Point::get_x_cnt += 1;return this->x; }int get_y() { return this->y; }//这里是直接定义了类方法static int x_cnt() {return Point::get_x_cnt;}private ://这里只是声明了这个变量//get_x_cnt,记录变量x在被get时,在整个程序执行时被调用了多少次static int get_x_cnt;int x, y;
};//这里就是定义了get_x_cnt, 并且给他的值进行了初始化
int Point::get_x_cnt = 0;int main() {Point p1(3, 4), p2(5, 6);cout << p1.get_x() << ", " << p1.get_y() << endl;cout << p2.get_x() << ", " << p2.get_y() << endl;p1.get_x();p1.get_x();p1.get_x();cout << "x_cnt : " << Point::x_cnt() << endl;return 0;
}

 const 方法

对于const和mutable关键字使用,对于上一份代码的修改:

#include<iostream>
using namespace std;class Point {public :Point() : x(0), y(0) , get_x_cnt(0){} //默认构造Point(int x, int y) : x(x), y(y), get_x_cnt(0) {} //有参构造void set_x (int x) { this->x = x; }void set_y (int y) { this->y = y; }int get_x() const { //修改处get_x_cnt += 1;return this->x; }int get_y() const { return this->y; }//修改处int x_cnt() const {//修改处return get_x_cnt;}private ://现在get_x_cnt,表示当前对象对get_x函数的调用次数//mutable关键字表示不收const关键之的限制//所以就算有const关键字,那么mutable声明的变量也可以进行修改mutable int get_x_cnt;int x, y;
};int main() {const Point p(10, 15), p2(1, 2);cout << p.get_x() << ", " << p.get_y() << endl;p2.get_x();p2.get_x();cout << "p1 : get_x_cnt = " << p.x_cnt() << endl;cout << "p2 : get_x_cnt = " << p2.x_cnt() << endl;return 0;
}

类的声明和定义

还是对类属性和类方法的那份代码进行修改:

#include<iostream>
using namespace std;//在类中只放方法的声明
class Point {public :Point();Point(int x, int y);void set_x (int x);void set_y (int y);int get_x() const;int get_y() const;static int x_cnt();private :static int get_x_cnt;int x, y;
};//对于类中的方法进行实现
//那么就可以将这两部分拆开
//定义放在源文件中,声明放在头文件中
Point::Point() : x(0), y(0) {}
Point::Point(int x, int y) : x(x), y(y) {}
void Point::set_x(int x) {this->x = x; 
}void Point::set_y(int y) {this->y = y; 
}int Point::get_x() const{Point::get_x_cnt += 1;return x; 
}int Point::get_y() const{return y;
}int Point::x_cnt() {return Point::get_x_cnt; 
}int Point::get_x_cnt = 0;int main() {Point p1(3, 4), p2(5, 6);cout << p1.get_x() << ", " << p1.get_y() << endl;cout << p2.get_x() << ", " << p2.get_y() << endl;p1.get_x();p1.get_x();p1.get_x();cout << "x_cnt : " << Point::x_cnt() << endl;return 0;
}

default和delete关键字

    delete和default关键字引用代码:

#include<iostream>
using namespace std;class A {
public ://A() = delete;A() {cout << "default constructor" << endl;}A(int n) : x(n) {cout << "conversion constructor" << endl;}A(const A &) {cout << "copy constructor" << endl;}
private :int x;
};class B {
public :B() = default;B(const B&) = default;
private :A a1, a2, a3;
};class C {
public :C() = default;//C(const C&) {}//这种情况叫撒比构造C(const C&) = default;
private :A a1, a2, a3;
};class Point {
public :Point() = default;//请求编译器生成默认构造函数Point(int x, int y) : x(x), y(y) , p(new int(5)), a(1){}//Point(const Point &) = delete;//删除编译器的拷贝构造函数//Point(const Point &) = default;//拷贝函数生成默认行为,在使用这个拷贝构造函数时就会造成双重释放的报错//这就是深拷贝Point(const Point &a) : x(a.x + 1), y(a.y + 2), a(a.a){//如果这里成员属性a直接用这样去赋值拷贝//那么成员属性a就会使用A类的默认构造函数进行构造//而A类的默认构造函数已经被删除了,那么就会报错//this->a = a.a;this->p = new int;*(this->p) = *(a.p);}~Point() {delete p;}
private :A a;int *p;int x, y;
};int main() {Point p1(1, 2), p2 = p1;return 0;
}

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

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

相关文章

多标签与多分类的区别

多标签与多分类的区别 多标签多分类样本类别个数一个或多个只有一个输出一个标签维度的向量&#xff0c;每一维度是类别的概率[0.1, 0.6, 0.1, 0.1, 0.8]输出属于每个类别的概率[0.1, 0.6, 0.1, 0.1, 0.1]标签多标签的每一维度都是0或者1&#xff0c;类别可以共存&#xff0c;…

移除元素(C++)

给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面…

line 1:20 no viable alternative at input ‘point,‘

背景 遇到一个蛋疼的问题&#xff0c;搞得老夫难受的一&#xff0c;解决了索性记录下 Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession61b0005f] was not registered for synchronization because synchronization is not activ…

coco128数据对象类别中英文对照json格式

中英对照 jsonarray [{id: 0,person: 人 }, {id: 1,bicycle: 自行车 }, {id: 2,car: 汽车 }, {id: 3,motorcycle: 摩托车 }, {id: 4,airplane: 飞机 }, {id: 5,bus: 公交车 }, {id: 6,train: 火车 }, {id: 7,truck: 卡车 }, {id: 8,boat: 船 }, {id: 9,trafficlight: 红绿灯 }…

java学习笔记8

15. 多态 15.1 多态概念 ​ java中**多态(Polymorphism )**是指不同对象在调用相同名称方法时,表现的多种不同行为。例如,要实现一个动物叫的方法,由于每种动物的叫声不同,因此可以在方法中接收一个动物参数,当传入的是猫类时发出猫叫,传入狗类时发出狗的叫声。 ​ ja…

python爬虫-----深入了解 requests 库(第二十五天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

安卓接收后台数据转模型int默认为double

问题&#xff1a;后台登录接口返回userid&#xff08;int整型10000&#xff09;&#xff0c;app前端&#xff08;使用okgo&#xff09;拿到userid&#xff08;double类型10000.0&#xff09;&#xff1b;导致app前端进行接下来操作如App中a用户使用userid转字符串后“10000.0”…

openAI tts Java文本转语音完整前后端代码 html

Java后端代码 maven 仓库&#xff1a; <!--openAI 请求工具--> <dependency><groupId>com.unfbx</groupId><artifactId>chatgpt-java</artifactId><version>1.1.5</version> </dependency>maven 仓库官方 tts 使用案例…

浅析RED和EN 18031

文章目录 前言欧盟的法律文件什么是REDRED的发展EU 2022/30法规EU 2023/2444RED与EN 18031的关系 前言 提示&#xff1a;本文大致表述了欧盟的一些立法常识&#xff0c;RED的由来与发展&#xff0c;以及它跟EN 18031的关系 因为工作原因&#xff0c;最近稍微研究了一下欧盟即将…

微波炉定时器开关

微波炉火力调节开关及定时器开关内部结构 参考链接&#xff1a; 微波炉火力调节开关及定时器开关判断好坏小经验-百度经验 (baidu.com)https://jingyan.baidu.com/article/5d6edee2d175c399eadeecfd.html微波炉拆解图示&#xff0c;微波炉结构原理&#xff0c;轻松玩转微波炉维…

DataLoader批量读取数据

使用DataLoader的小例子&#xff0c;这里CustomDataset类的__getitem__方法需要返回tensor。 加载到DataLoader中之后&#xff0c;DataLoader会通过类似字典的方式读取CustomDataset中的数据&#xff0c;达到批量处理的效果。 import torch from torch.utils.data import Datas…

AI大模型探索之路-应用篇14:认识国产开源大模型GLM

目录 前言 一、国产主流大模型概览 1. 国内主流大模型清单 2. 主流大模型综合指数 3. 大语言模型评测榜单 二、GLM大模型介绍 三、GLM大模型发展历程 四、GLM家族之基座模型GLM-130B 五、GLM家族之ChatGLM3 六、GLM家族之WebGLM 七、GLM家族之CogVLM 1. CogVLM 2. …

IP地址和物理地址的理解

1. 引言 最近在学习计算机网络相关知识&#xff0c;很长时间都有个困惑&#xff0c;为什么TCP/IP协议栈中会有2中地址&#xff0c;即&#xff1a;IP地址和物理地址&#xff08;MAC地址&#xff09;为什么同时被使用&#xff1f;它们各自的作用是啥&#xff1f; 2.我的理解 在写…

春招冲刺百题计划|栈

Java基础复习 Java数组的声明与初始化Java ArrayListJava HashMapJava String 类Java LinkedListJava Deque继承LinkedListJava Set 第一题&#xff1a;有效的括号 很简单的题&#xff0c;从大一做到现在&#xff0c;就是复习一下语法。 class Solution {public boolean i…

系统架构最佳实践 -- 新能源汽车产业架构设计

随着环保意识的增强和能源结构的转型&#xff0c;新能源汽车产业正迅速崛起成为汽车行业的新宠。构建一个完善的新能源汽车产业架构对于推动产业发展、提升竞争力至关重要。本文将从设计原则、关键技术、产业生态等方面&#xff0c;探讨如何设计与实现新能源汽车产业架构。 新能…

LabVIEW专栏六、LabVIEW项目

一、梗概 项目&#xff1a;后缀是.lvproj&#xff0c;在实际开发的过程中&#xff0c;一般是要用LabVIEW中的项目来管理代码&#xff0c;也就是说相关的VI或者外部文件&#xff0c;都要放在项目中来管理。 在LabVIEW项目中&#xff0c;是一个互相依赖的整体&#xff0c;可以包…

Python List 列表基础知识

1、什么是列表&#xff1f; 在实际开发中&#xff0c;经常需要将一组&#xff08;不只一个&#xff09;数据存储起来&#xff0c;以便后边的代码使用。说到这里&#xff0c;一些读者可能听说过数组&#xff08;Array&#xff09;&#xff0c;它就可以把多个数据挨个存储到一起…

springboot针对thymeleaf的使用总结

1、遍历 <ul th:if"${not #lists.isEmpty(nav.articleTypeList)}"><li th:each"articleType,articleTypeStat:${nav.articleTypeList}"></li> </ul> 注释&#xff1a;其中${not #lists.isEmpty(list)}先判断list非空&#xff0c…

数据结构:哈密顿回路基础

什么是哈密顿回路&#xff1f; 哈密顿回路&#xff08;Hamiltonian Cycle&#xff09;是图论中的一个概念&#xff0c;指的是在一个图中通过图的每个顶点恰好一次且仅一次&#xff0c;并最终回到起始顶点的闭合回路。在一个哈密顿回路中&#xff0c;除了起始和结束的顶点必须是…

TongRds docker 镜像做成与迁移(by liuhui)

TongRds docker 镜像做成与迁移 一&#xff0c;使用 docker commit 命令制作 TongRds docker 镜 像 1.1 拉取基础镜像 centos 并运行该镜像 拉取镜像&#xff1a;docker pull ubuntu 镜像列表&#xff1a;docker images 运行镜像&#xff1a;docker run -itd --name myubuntu…