【第二天】C++类和对象解析:构造函数、析构函数和拷贝构造函数的完全指南

news2024/12/29 0:41:19

一、类的引出概述

        在c语言结构体中,行为和属性是分开的,万一调用错误,将会导致问题发生。c++中类将数据方法封装在一起,加以权限区分,用户只能通过公共方法 访问 私有数据

二、封装

        封装特性包含两个方面,一个是属性和变量合成一个整体,一个是给属性和函数增加访问权限

1.把变量(属性)和函数(操作)合成一个整体,封装在一个类中

2.对变量和函数进行访问控制访问权限
3.在类的内部(作用域范围内),没有访问权限之分,所有成员可以相互访问

4.在类的外部(作用域范围外),访问权限才有意义:.public、private、protected

5.在类的外部,只有public.修饰的成员太能被访问,在没有涉及继承与派生时,private和protected是相同等级的.外部不允许访问        

访问属性属性对象内部对象外部
public公有可访问可访问
private保护可访问不可访问
protected私有可访问不可访问

尽量设置成员变量为私有权限,将方法设置成公有。

优点:

对变量的设置时的控制

实现变量设置只读权限

实现变量设置只写权限

实现变量设置可读可写权限

struct和class的区别:class默认访问权限为.private,struct默认访问权限为public.

三、类的案例(了解)

1、设计一个person类

        设计一个Person类,Person类具有name和age属性,提供初始化函数(Init),并提供对name和age 的读写函数(set,get),但必须确保age的赋值在有效范围内(0-100),超出有效范围,则拒绝赋值,并 提供方法输出姓名和年龄。----需要六个函数

#include <iostream>
using namespace std;
#include<string.h>
class Person
{
private:
    char mName[32];
    int mAge;
public:
    //初始化成员
    void init(char *name, int age)
    {
        strcpy(mName, name);
        if(age>=0 && age<=100)
        {
            mAge = age;
        }
        else
        {
            cout<<"年龄无效"<<endl;
        }
        return;
    }
    //设置name
    void setName(char *name)
    {
        strcpy(mName, name);
    }
     //获取name
    char *getName(void)
    {
         return mName;
     }
    //设置age
    void setAge(int age)
    {
        if(age>=0 && age<=100)
        {
            mAge = age;
        }
        else
        {
            cout<<"年龄无效"<<endl;
        }
    }
    //得到age
    int getAge(void)
    {
        return mAge;
    }
    //显示所有数据
    void showPerson(void)
    {
        cout<<mName<<" "<<mAge<<endl;
    }
};
void test02()
{
    Person ob1;
    ob1.init("lucy", 18);
    ob1.showPerson();
    ob1.setName("bob");
    cout<<"年龄:"<<ob1.getAge()<<endl;
    ob1.showPerson();
}

2、设计一个立方体类

        设计立方体类(Cube),求出立方体的面积( 2ab +2ac +2bc )和体积( a*b*c),分别用全局函数和成员函数判断两个立方体是否相等。

class Cube
{
private:
    int mA;
    int mB;
    int mC;
    public:
    void setA(int a)
    {
        mA = a;
    }
    int getA(void)
    {
        return mA;
    }
    void setB(int b)
    {
        mB = b;
    }
    int getB(void)
    {
    return mB;
    }
    void setC(int c)
    {
        mC = c;
    }
    int getC(void)
    {
        return mC;
    }
    //获取面积
    int getS(void)
    {
        return (mA*mB+mB*mC+mC*mA)*2;
    }
    //获取体积
    int getV(void)
    {
        return mA*mB*mC;
    }
    //成员函数 比较两个立方体是否先等
    bool compareCube01(Cube &ob)
    {
        if(mA==ob.mA && mB ==ob.mB && mC == ob.mC)
    {
        return true;
    }
        return false;
    }
};

//全局函数 比较两个立方体是否先等
bool compareCube02(Cube &ob1, Cube &ob2)
{
    if(ob1.getA()==ob2.getA() && ob1.getB() ==ob2.getB() && ob1.getC() == ob2.getC())
    {
        return true;
    }
        return false;
}
    void test()
{
    Cube ob1;
    ob1.setA(10);
    ob1.setB(20);
    ob1.setC(30);
    cout<<"面积:"<<ob1.getS()<<endl;
    cout<<"体积:"<<ob1.getV()<<endl;
    Cube ob2;
    ob2.setA(10);
    ob2.setB(20);
    ob2.setC(30);
    // if(compareCube02(ob1, ob2))
    if(ob1.compareCube01(ob2))
    {
        cout<<"相等"<<endl;
    }
    else
    {
        cout<<"不相等"<<endl;
    }
}
int main(int argc, char *argv[])
{
    test();
    return 0;
}

3、点和圆的关系

        设计一个圆形类(AdvCircle),和一个点类(Point),计算点和圆的关系。

class Point
{
private:
    int mX;
    int mY;
public:
    void setX(int x)
    {
        mX = x;
    }
    int getX(void)
    {
        return mX;
    }
    void setY(int y)
    {
        mY = y;
    }
    int getY(void)
    {
        return mY;
    }
};
class Circle
{
private:
    Point p;//对象作为类的成员变量
    int mR;
public:
    void setPoint(int x, int y)
    {
        p.setX(x);
        p.setY(y);
    }
    Point getPoint(void)//打印圆点
    {
        return p;
    }
    void setR(int r)
    {
        mR = r;
    }
    int getR(void)
    {
        return mR;
    }
    //判断点 在圆的位置
    int pointIsOnCircle(Point &ob)
    {
        int len = (ob.getX()-p.getX())*(ob.getX()-p.getX())+\
        (ob.getY()-p.getY())*(ob.getY()-p.getY());
        if(len == mR*mR)
        {
            return 0;
        }
        else if(len > mR*mR)
        {
            return 1;
        }
        else if(len < mR*mR)
        {
            return -1;
        }
    }
};
void test()
{
//实例化一个点的对象
    Point p;
    p.setX(5);
    p.setY(5);
    //实例化一个圆的对象
    Circle cir;
    cir.setPoint(2,2);
    cir.setR(5);
    if(cir.pointIsOnCircle(p) == 0)
    {
        cout<<"点在圆上"<<endl;
    }
    else if(cir.pointIsOnCircle(p) > 0)
    {
        cout<<"点在圆外"<<endl;
    }
    else if(cir.pointIsOnCircle(p) < 0)
    {
        cout<<"点在圆内"<<endl;
    }
}

4、类中成员函数在类外实现

5、类在其他文件实现

        头文件定义类, cpp实现类的成员函数

data.h

#ifndef DATA_H
#define DATA_H
class Data
{
private:
    int mA;
public:
    int getA(void);
    void setA(int a);
};
#endif 

 data.cpp

#include "data.h"
int Data::getA()
{
    return mA;
}
void Data::setA(int a)
{
    mA = a;
}

main.cpp

#include <iostream>
#include "data.h"
using namespace std;
int main(int argc, char *argv[])
{
    Data ob;
    ob.setA(100);
    cout<<ob.getA()<<endl;
    return 0;
}

对象的构造和析构:

        当我们创建对象的时候,这个对象应该有一个初始状态,当对象销毁之前应该销毁自己创建的一些数据。对象的初始化清理也是两个非常重要的安全问题,C++为了给我们提供这种问题的解决方案,构造函数和析构函数,这两个函数将会被编译器自动调用完成对象初始化(创建对象时为对象成员属性赋值)和对象清理工作。初始化和清理工作是编译器强制我们要做的事情,即使你不提供初始化操作和清理操作,编译器也会给你增加默认的操作,只是这个默认初始化操作不会做任何事。

四、构造函数(初始化工作)

1、概述

        构造函数是类实例化对象时自动调用

2、创建

        构造函数名与类名称相同,不能有返回值类型(连void都不可以),可以有参数(支持重载),必须加public权限。

3、分类

        无参构造、有参构造。

4、调用

        类实例化对象时:先为对象开辟空间 然后才调用构造函数。 

1、如果用户不提供构造函数 编译器会自动 提供一个无参空的构造函数。

2、如果用户提供构造函数 编译器会自动 屏蔽默认无参的构造

四种:隐式调用、显示调用、隐式转换、匿名调用 

注:写任何一个类 无参构造, 有参构造都需要实现 

5、explicit关键字防止构造函数隐式转换

        explicit修饰构造函数,防止构造函数隐式转换,避免令人产生赋值误会。

允许隐式转换:

//此时允许有参构造隐式转换
A(int a)
{
    mA = a;
    cout<<"A的有参构造mA="<<mA<<endl;
}
//构造函数隐式转换(类中只有一个数据成员)
A ob1=100;//ok

不允许隐式转换:

//防止有参构造 隐式转换
explicit A(int a)
{
    mA = a;
    cout<<"A的有参构造mA="<<mA<<endl;
}
//构造函数隐式转换(类中只有一个数据成员)
A ob1=100;//err 转换失败

五、析构函数(清理工作)

         当对象生命周期结束的时候 系统自动调用析构函数。

        函数名和类名称相同,在函数名前加~,没有返回值类型,没有函数形参。(不能被重载) 先调用析构函数 再释放对象的空间。

调用释放顺序:括号内的最先释放,释放先进后出

         一般情况下,空的析构函数就足够。但是如果一个类有指针成员,这个类必须 写析构函数,释放指针成员所指向空间。

#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
class Data
{
public:
	char *name;
public:
	Data()
	{
		name = NULL;
	}
	Data(char *str)
	{
		name = (char*)calloc(1, strlen(str) + 1);
		strcpy(name, str);
		cout << "有参构造 name=" << name << endl;
	}
	~Data()
	{
		cout << "析构函数" <<name<< endl;
		if (name != NULL)
		{
			free(name);
			name = NULL;
		}
	}
 };
void test()
{	
	Data ob("hello world");
}

六、拷贝构造函数

1、定义

        拷贝构造函数本质是构造函数

        拷贝构造的调用时机:对象 初始化 对象 时。

 如果用户不提供拷贝构造 编译器会自动提供一个默认的拷贝构造(完成赋值动作--浅拷贝)

2、拷贝构造 和 无参构造 有参构造的关系

如果用户定义了 拷贝构造或者有参构造 都会屏蔽无参构造。

如果用户定义了 无参构造或者有参构造 不会屏蔽拷贝构造。

3、拷贝构造调用形式

(1)旧对象给新对象初始化 调用拷贝构造

Data ob1(10);
Data ob2 = ob1;//调用拷贝构造

(2)普通对象作为函数参数 调用函数时 会发生拷贝构造 

(3)函数返回值普通对象 (Visual Studio会发生拷贝构造) 

Data get(void)
{
	Data ob1(10);
	return ob1;
}
void test()
{	
	Data ob2 = get();
}

注:给对象取别名 不会调用拷贝构造 

Data ob1(10);
Data &ob2 = ob1;//不会调用拷贝构造

4、拷贝构造中浅拷贝和深拷贝

        如果类中没有指针成员, 不用实现拷贝构造和析构函数。

        如果类中指针成员和拷贝构造调用, 必须实现析构函数释放指针成员指向的堆区空间,必须实现拷贝构造完成深拷贝动作(因拷贝构造释放时相应堆区空间需再释放一次,故堆区空间也需重新拷贝一次)

 七、初始化列表

成员对象:一个类的对象 作为另一个类的成员

类会自动调用成员对象的无参构造,如果类中想调用成员对象有参构造 必须使用初始化列表

class A
{
public:
	int mA;
public:
	A()
	 {
		 mA = 0;
		cout << "A的无参构造" << endl;
		 }
	 A(int a)
		{
		 mA = a;
		 cout << "A的有参构造" << endl;
		 }
	~A()
	 {
		 cout << "A的析构函数" << endl;
	 }
};
class B
{
public:
	 int mB;
	A ob;//成员对象
public:
	B()
	{
		cout << "B类的无参构造" << endl;
	 }
		//初始化列表 成员对象 必须使用对象名+() 重要
	 B(int a, int b) :ob(a)
	{
		 mB = b;
		cout << "B类的有参构造" << endl;
	}
	~B()
	 {
		cout << "B的析构函数" << endl;
	 }
 };
int main(int argc, char* argv[])
{
	 B ob1(10, 20);
	 cout << "mA =" << ob1.ob.mA << ", mB =" << ob1.mB << endl;
	return 0;
 }

 八、对象数组

        对象数组:本质是数组 数组的每个元素是对象

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

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

相关文章

Java 中的 Default 关键字

default 关键字&#xff1a;是在 Java 8 中引入的新概念&#xff0c;也可称为 Virtual extension methods——虚拟扩展方法与public、private等都属于修饰符关键字&#xff0c;与其它两个关键字不同之处在于default关键字大部分都用于修饰接口。 default 修饰方法时只能在接口…

基于Java+Springboot+Vue前后端分离的商品库存销售管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 当今社会&#xff0c;…

混合专家模型 Mixture-of-Experts (MoE)

大纲 Mixture-of-Experts (MoE)Mixture of Sequential Experts&#xff08;MoSE&#xff09;Multi-gate Mixture-of-Experts (MMoE) 一、MoE 1. MoE架构 MoE&#xff08;Mixture of Experts&#xff09;层包含一个门网络&#xff08;Gating Network&#xff09;和n个专家网…

中文编程开发语言工具编程实际案例:台球棋牌混合计时计费软件使用的编程构件说明

中文编程开发语言工具编程实际案例&#xff1a;台球棋牌混合计时计费软件使用的编程构件说明 上图说明&#xff1a;该软件可以用于桌球和棋牌同时计时计费&#xff0c;在没有开台的时候&#xff0c;图片是处于等待状态&#xff0c;这使用编程工具中的固定图像构件&#xff0c;在…

【经典 PageRank 】01/2 PageRank的基本原理

一、说明 PageRank是Google搜索算法中使用的一种算法&#xff0c;用于确定页面的重要性和排名。 它是通过对网页间的链接关系进行评估来计算的&#xff0c;具有较高的链接权重的网页将获得较高的PageRank值。 PageRank是一个0到10的指标&#xff0c;其中10是最高级别&#xff0…

正点原子嵌入式linux驱动开发——Linux并发与竞争

Linux是一个多任务操作系统&#xff0c;肯定会存在多个任务共同操作同一段内存或者设备的情况&#xff0c;多个任务甚至中断都能访问的资源叫做共享资源。在驱动开发中要注意对共享资源的保护&#xff0c;也就是要处理对共享资源的并发访问。在Linux驱动编写过程中对于并发控制…

前端TypeScript学习day05-索引签名、映射与类型声明文件

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 索引签名类型 映射类型 索引查询&#xff08;访问&#xff09;类型 基本使用 同时查询多个索引的类型…

2023天猫双十一活动时间表 天猫淘宝双11预售几号开始付定金

双十一购物节是生活不可或缺的一部分&#xff0c;不论是满足基本需求还是享受生活乐趣&#xff0c;都需要购物。因此&#xff0c;双十一绝对是一个不容错过的绝佳机会&#xff0c;希望大家能善用这个机会&#xff0c;因为错过了就得再等一整年。 每日领红包&#xff1a;红包有…

基于袋獾优化的BP神经网络(分类应用) - 附代码

基于袋獾优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于袋獾优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.袋獾优化BP神经网络3.1 BP神经网络参数设置3.2 袋獾算法应用 4.测试结果&#xff1a;5.M…

MYSQL第一章节DDL数据定义语言的操作(DDL-数据库操作,DDL-操作表-查询,DDL-操作表-修改,数据库的基本类型)

c知识点合集已经完成欢迎前往主页查看&#xff0c;点点赞点点关注不迷路哦 点我进入c第一章知识点合集 MYSQL第一章节DDL数据定义语言的操作 目录 DDL-数据库操作 查询所有数据库 查询当前数据库 创建数据库 删除数据库 DDL-操作表-查询 查询当前数据库中的所有表 查询表结构…

基于斑马优化的BP神经网络(分类应用) - 附代码

基于斑马优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于斑马优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.斑马优化BP神经网络3.1 BP神经网络参数设置3.2 斑马算法应用 4.测试结果&#xff1a;5.M…

【iOS】MVC模式

MVC&#xff08;Model-View-Controller&#xff0c;模型-视图-控制器&#xff09;模式是相当古老的设计模式之一&#xff0c;ta最早出现在SmallTalk语言中。现在&#xff0c;很多计算机语言和架构都采用了MVC模式。 MVC模式概述 MVC模式是一种设计模式&#xff0c;由3部分组成…

图论05-【无权无向】-图的广度优先遍历-路径问题/检测环/二分图/最短路径问题

文章目录 1. 代码仓库2. 单源路径2.1 思路2.2 主要代码 3. 所有点对路径3.1 思路3.2 主要代码 4. 联通分量5. 环检测5.1 思路5.2 主要代码 6. 二分图检测6.1 思路6.2 主要代码6.2.1 遍历每个联通分量6.2.2 判断相邻两点的颜色是否一致 7. 最短路径问题7.1 思路7.2 代码 1. 代码…

基于SSM的物业管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

AdaBoost:增强机器学习的力量

一、介绍 机器学习已成为现代技术的基石&#xff0c;为从推荐系统到自动驾驶汽车的一切提供动力。在众多机器学习算法中&#xff0c;AdaBoost&#xff08;自适应增强的缩写&#xff09;作为一种强大的集成方法脱颖而出&#xff0c;为该领域的成功做出了重大贡献。AdaBoost 是一…

数据分析案例-顾客购物数据可视化分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

今年阿里云双十一服务器优惠价格讨论_看看大家怎么说?

2023阿里云双十一云服务器大概会降到什么区间&#xff1f;阿里云服务器网认为会在当前的优惠价格基础上&#xff0c;降价10%左右&#xff0c;可以在阿里云CLUB中心领券&#xff1a;aliyun.club 云服务器专用满减优惠券。阿里云服务器网从各个渠道了解到大家对今年阿里云双十一服…

在用visualstudio连接数据库显示已存在以及此版本的SQLServer不支持用户实例登录解决

在写.NET实验时用visualstudio连接数据库显示”此版本的 SQL Server 不支持用户实例登录标志。该连接将关闭“&#xff0c;我是开始在数据库已经导入了这个mbf文件的。然后就去网上找一堆办法。 失败经历&#xff1a; 按照教程操作后代码语句运行显示数据库已存在。按照网上的…

王道计算机考研 操作系统学习笔记 + 完整思维导图篇章四: 文件管理

目录 文件管理 文件的逻辑结构 无结构文件 有结构文件 顺序文件 索引文件 索引顺序文件 文件目录 文件控制块&#xff08;FCB&#xff09; 目录结构分类 单级目录结构 两级目录结构 多级目录结构 &#xff08;树形目录结构&#xff09; 无环图目录结构 索引节点 文件的物理结构…

【经典PageRank 】02/2 算法和线性代数

系列前文&#xff1a;【经典 PageRank 】01/2 PageRank的基本原理-CSDN博客 一、说明 并非所有连接都同样重要&#xff01; 该算法由 Sergey 和 Lawrence 开发&#xff0c;用于在 Google 搜索中对网页进行排名。基本原则是重要或值得信赖的网页更有可能链接到其他重要网页。例…