C++ Day3

目录

一、类

【1】类

【2】应用实例

练习:

【3】封装

二、this指针

 【1】this指针的格式

【2】必须使用this指针的场合

三、类中的特殊成员函数

【1】构造函数

i)功能

ii)格式

iii)构造函数的调用时机

iv)构造函数允许函数重载

v)构造函数的初始化列表

1.格式:

2.必须使用初始化列表的情况:

2】析构函数

i)功能

ii)调用时机

iii)格式

iv)需要显性定义出析构函数的情况

【3】拷贝构造函数

i)功能

ii)格式

iii)调用时机

iv)深浅拷贝问题

【4】拷贝赋值函数

i)功能

ii)格式

作业:


一、类

面向对象的三大特征:封装、继承和多态

C++中封装是由类来实现的

C++中的类是由结构体演变而来的

结构体:变量和函数

类:成员属性(变量)、成员方法(函数)

【1】类

类中成员默认是private权限

class 类名
{
public:       ---->类外和类内都可以访问公有的成员变量/函数
private:      ---->类内可以访问,类外不能访问私有的成员变量/函数
protected:受保护的成员变量/函数    
};

【2】应用实例

#include <iostream>
using namespace std;class Person
{
private:string name;
public:int age;int high;void set_name(string n);    //在类内声明函数void show(){cout << "name = "<< name << " age = "<<age << " high = "<<high << endl;}
};int main()
{Person p1;       //实例化一个类对象p1p1.set_name("zhangsan");p1.age = 90;p1.high = 100;p1.show();return 0;
}//类外实现
void Person::set_name(string n)
{name = n;
}

练习:

1、定义一个矩形类(Rectangle),包含私有成员长(length)、宽(width),定义成员函数:

设置长度: void set_len(int l);

设置宽度: void set_wid(int w);

获取长度: int get_len();

获取宽度: int get_wid();

显示周长和面积: void show();

#include <iostream>
using namespace std;class Rec
{int length;int width;
public://所有函数的类内声明void set_len(int l);void set_wid(int w);int get_len();int get_wid();void show();};void Rec::set_len(int l)
{length = l;
}
void Rec::set_wid(int w)
{width = w;
}
int Rec::get_len()
{return length;
}
int Rec::get_wid()
{return width;
}
void Rec::show()
{cout << "周长" << 2*(length+width) << endl;cout << "面积" << length*width << endl;
}
int main()
{Rec r1;    //实例化了一个Rec类的类对象r1r1.set_len(10);r1.set_wid(3);cout << "长:" << r1.get_len() << endl;cout << "宽:" << r1.get_wid() << endl;r1.show();return 0;
}

【3】封装

  1. 把某一事物的所有属性(变量)、行为(成员方法/成员函数),封装成一个整体,给私有的属性,提供公有的接口,以便于用户修改
  2. 类中成员都有访问权限(public,private,protected)
  3. 访问权限,是对于整个类而言的
  4. 类中同一访问权限,可以可以出现多次
  5. 类中默认是私有权限

二、this指针

this指针,是类内默认提供给非静态成员函数的指针,this指向,指向类对象本身,哪个类对象调用函数,this就指向哪一个类对象(谁调用函数this就指向谁)

 【1】this指针的格式

类名 *const this;  ----->不能修改指针指向

【2】必须使用this指针的场合

  1. 当成员函数的参数和类中成员属性同名时,需要使用this指向表明哪一个是类中的成员属性
  2. 拷贝赋值函数中,需要返回自身的引用,也需要使用this指针
#include <iostream>
using namespace std;class Rec
{int length;int width;
public://所有函数的类内声明void set_len(int length);void set_wid(int width);int get_len();int get_wid();void show();
};void Rec::set_len(int length)
{this->length = length;
}void Rec::set_wid(int width)
{this->width = width;
}int Rec::get_len()
{return length;
}int Rec::get_wid()
{return width;
}void Rec::show()
{cout << "周长" << 2*(length+width) << endl;cout << "面积" << length*width << endl;
}
int main()
{Rec r1;    //实例化了一个Rec类的类对象r1Rec r2;r2.set_len(20);r1.set_len(10);r1.set_wid(3);cout << "长:" << r1.get_len() << endl;cout << "宽:" << r1.get_wid() << endl;r1.show();return 0;
}

三、类中的特殊成员函数

类中的特殊成员函数,程序员如果不手动写出来,系统会默认提供

一共有6个特殊的成员函数:构造函数、析构函数、拷贝构造函数、拷贝赋值函数,取地址运算符的重载和常取地址运算符的重复,C++11又提供了:移动构造、移动赋值函数

本文只有前四个

【1】构造函数

用于实例化类对象,系统会自动调用,系统自动提供的是无参构造

如果手动定义了构造函数,那么系统不会再提供一个无参构造

i)功能

实例化类对象时,申请空间使用的

ii)格式

类名(参数)
{函数体;
}

iii)构造函数的调用时机

栈区:什么时候实例化类对象,什么时候调用

在 C++ 中,对象可以在栈区实例化,这也被称为自动存储类对象。实例化对象时,会在栈上为对象分配内存空间,并调用对应的构造函数进行初始化。
对象的实例化和调用可以发生在不同的情况下:

1.在函数内部:当在函数内部定义一个类对象时,对象的实例化和构造函数的调用将发生在函数的作用域内。例如:

void foo() {MyClass obj;  // 实例化对象并调用构造函数// 函数内的其他操作
} // 函数结束,对象超出作用域,析构函数将会被调用


2.作为类的成员:如果一个类定义在另一个类中,并作为成员变量,那么对象的实例化和构造函数的调用将随着父类对象的实例化而发生。例如:

class ParentClass {
public:MyClass obj;  // 对象作为成员变量
};int main() {ParentClass parentObj;  // 实例化父类对象,对象的实例化和构造函数调用都会发生// 其他操作
} // 父类对象超出作用域,析构函数将会被调用,对象的析构顺序与构造相反

需要注意的是,在栈上实例化的对象会在其所在的作用域结束时超出作用域,从而自动调用析构函数,释放对象占用的内存空间。这种自动释放内存的方式称为自动存储管理。

堆区:定义类的指针时,不调用构造函数。

什么时候new,什么时候调用 :应该在对象不再使用时调用对应的析构函数来释放内存,以避免内存泄漏。

iv)构造函数允许函数重载

  1. 系统默认提供一个无参构造函数
  2. 可以显性定义出有参构造,但是此刻系统不再提供默认的无参构造,还可以显性写出无参构造
  3. 构造函数是允许函数重载的
#include <iostream>
using namespace std;class Stu
{string name;int age;
public://定义Stu类的无参构造Stu(){cout << "Stu的无参构造" << endl;}//函数重载Stu(string name,int age){this->name = name;this->age = age;cout << "Stu的有参构造" << endl;}Stu(string name){this->name = name;cout << "Stu的对name的有参构造" << endl;}
};int main()
{     Stu s1("zhangsan",18);  //栈区的类对象Stu *p;  //在栈区申请一个Stu*类型的指针p = new Stu("lisi");    //在堆区申请一个Stu的空间,会调用构造函数return 0;
}

v)构造函数的初始化列表

1.格式:

类型(形参):成员属性1(形参1),成员属性2(形参2),······{函数体内容} 

  1. 构造函数提供了初始化列表的机制,可以直接在函数体外执行初始化操作

  2. 初始化列表由:引出,每一个成员属性的值之间以,逗号分隔

2.必须使用初始化列表的情况:

  1. 形参和成员属性同名
  2. 类中有引用成员时,需要使用初始化列表
  3. 类中有const修饰的成员时
  4. 一个类中有另一个类的子对象时,需要使用初始化列表(如果两个类都有无参构造,是不需要写初始化列表)

 

//包含其他类的子对象
#include <iostream>
using namespace std;
class Per
{string name;
public://Per提供的有参构造Per(string name){this->name = name;cout << "Per的有参构造" << endl;}Per(){cout << "Per的无参构造" << endl;}//一个show函数,输出namevoid show(){cout << "Per中的name=" << name << endl;}
};class Stu
{int score;
public:Per p1;    //Stu类中,包含另一个类的子对象,且另一个类只有有参构造函数
public:Stu(string name):p1(name)    //必须使用初始化列表,并且在初始化列表显性调用另一个类的构造函数{cout << "Stu的有参构造" << endl;}Stu(){cout << "Stu的无参构造" << endl;}
};int main()
{Stu s1("zhangsan");//通过s1这个类对象,调用Per中的show函数s1.p1.show();Stu s2;return 0;
}//同名或者是包含引用成员/const修饰的成员
class Stu
{string name;//int &age;     //类中有引用成员const int score;
public://定义Stu类的无参构造
//    Stu()
//    {
//        cout << "Stu的无参构造" << endl;
//    }//函数重载,使用初始化列表的方式//初始化列表也可以解决形参和成员属性同名问题Stu(string name,int age):name(name),score(age)  //在函数体外给成员属性初始化{cout << "Stu的有参构造" << endl;}void show(){cout << name << " " << score << endl;}
};int main()
{     Stu s1("zhangsan",18);  //栈区的类对象s1.show();Stu *p;  //在栈区申请一个Stu*类型的指针p = new Stu("lisi",20);    //在堆区申请一个Stu的空间,会调用构造函数return 0;
}

2】析构函数

析构函数,不支持函数重载,并且析构函数只有:~类名(){}

不需要传参数,public权限

i)功能

回收类对象的空间

ii)调用时机

栈区:类对象消亡时,自动调用

堆区:什么时候delete,什么时候调用析构函数

先构造的后析构,后构造的先析构

iii)格式

~类名()
{函数体;
}

iv)需要显性定义出析构函数的情况

  1. 类中有指针成员,并且指针成员指向堆区的空间
  2. 如果直接调用普通的析构函数,类对象消亡后,没有办法再去释放掉堆区的空间,会造成内存泄漏

#include <iostream>
using namespace std;class Stu
{int *p;
public:Stu():p(new int)    //在不传参的情况下,给指针成员p用堆区的空间初始化{cout << "Stu无参构造" << endl;}Stu(int a):p(new int(a))   //在参数为整形变量的情况下,让p指向堆区申请的空间//但是把这篇空间的内容,用传过来的整形变量初始化{cout << "Stu的有参构造" << endl;}Stu(int *p)   //要求传过来的指针的值,一定是指向堆区空间{this->p = p;cout << "Stu传指针的有参构造" << endl;}~Stu(){//在析构之前释放堆区的空间cout << "准备释放空间:" << p << endl;delete p;p = nullptr;cout << "Stu的析构函数" << endl;}
};int main()
{Stu s1(90);return 0;
}

【3】拷贝构造函数

i)功能

使用已有的类对象,给类对象初始化的时候,自动调用拷贝构造函数

ii)格式

类名(类名 &other)
{函数体的内容;
}拷贝构造函数,是一个构造函数,
函数名:类名
形参:其他类对象的引用

iii)调用时机

  1. 使用已有的类对象给新的类对象初始化
  2. 当函数的形参是一个类对象时,也会调用拷贝构造函数
  3. 当函数的返回值是一个类对象时,也会调用拷贝构造函数
#include <iostream>
using namespace std;
class Stu
{string name;
public:Stu(){cout << "Stu的无参构造" << endl;}Stu(string name){this->name = name;cout << "Stu的有参构造" << endl;}Stu(Stu &other)   //Stu的拷贝构造函数,和无参构造以及有参构造构成函数冲澡{this->name = other.name;cout << "Stu的拷贝构造函数" << endl;}void show(){cout << name << endl;}
};
Stu fun(Stu s1)  //定义了一个函数fun,形参是一个类对象
{cout << "调用成功" << endl;return s1;
}
int main()
{Stu s1("zhangsan");cout << "s1:";s1.show();Stu s2 = s1;   //拷贝构造函数cout << "s2:";s2.show();fun(s2);return 0;
}

 

iv)深浅拷贝问题

什么情况下发生:类中存在指针成员时

深拷贝:两个指针成员指向不同空间,但是取*的结果是一致

浅拷贝:两个指针成员指向同一片空间

1、对同一片空间二次释放问题

2、两个类对象使用同一片空间,发生资源抢占问题

#include <iostream>
using namespace std;class Stu
{int *p;
public:Stu():p(new int)    //在不传参的情况下,给指针成员p用堆区的空间初始化{cout << "Stu无参构造" << endl;}Stu(int a):p(new int(a))   //在参数为整形变量的情况下,让p指向堆区申请的空间//但是把这篇空间的内容,用传过来的整形变量初始化{cout << "Stu的有参构造" << endl;}Stu(int *p)   //要求传过来的指针的值,一定是指向堆区空间{this->p = p;cout << "Stu传指针的有参构造" << endl;}~Stu(){//在析构之前释放堆区的空间cout << "准备释放空间:" << p << endl;delete p;p = nullptr;cout << "Stu的析构函数" << endl;}void show(){cout << "p=" << p << endl;}void set_p(int a){*p = a;    //通过指针变量p,修改内存中的值}void show_p(){cout << *p << endl;  //通过指针变量,输出p指向的内存中的值}//拷贝构造函数Stu(Stu &other){p = new int;  //手动让s2的指针p指向堆区的空间//实现深拷贝*p = *(other.p);cout << "Stu的拷贝构造函数" << endl;}
};
int main()
{Stu s1(90);    //会给s1的指针成员在堆区申请一片空间使用90初始化Stu s2 = s1;   //申请了一个Stu的类对象的空间,也实现了用s1的值初始化s2//左调右参//上面一行,调用了拷贝构造函数//使用了默认提供的拷贝构造,会造成指针成员,指向同一片空间的问题
//    cout << "s1:";
//    s1.show();
//    cout << "s2:";
//    s2.show();s1.show_p();s2.show_p();s1.set_p(101);s1.show_p();s2.show_p();return 0;
}

【4】拷贝赋值函数

i)功能

使用已有的类对象,给已有的类对象赋值的时候,会调用拷贝赋值函数。

ii)格式

类名 &operator=(const 类名 &other)
{函数体;
}

作业:

设计一个Per类,类中包含私有成员:姓名、年龄、指针成员身高、体重,再设计一个Stu类,类中包含私有成员:成绩、Per类对象 p1,设计这两个类的构造函数、析构函数和拷贝构造函数。

#include <iostream>using namespace std;class Per{string name;int age;float* height;float* weight;
public://构造函数Per(string name,int age,float* height,float* weight){this->name = name;this->age = age;this->height = height;this->weight = weight;cout << "Per的构造函数" << endl;}//析构函数~Per(){delete height;delete weight;height = nullptr;weight = nullptr;cout << "Per的析构函数" << endl;}//拷贝构造函数Per(Per& other){this->name = other.name;this->age = other.age;height = new float;*height = *(other.height);weight = new float;*weight = *(other.weight);cout << "Per的拷贝构造函数" << endl;}void show(){cout << name << endl;}
};class Stu{float score;Per p1;
public://必须使用初始化列表的情况://形参和成员属性同名//类中有引用成员时,需要使用初始化列表//类中有const修饰的成员时//一个类中有另一个类的子对象时,需要使用初始化列表(如果两个类都有无参构造,是不需要写初始化列表)//Stu构造函数Stu(float score,string name,int age,float* height,float* weight):score(score),p1(name,age,height,weight){cout<< "Stu的构造函数" << endl;}//析构函数~Stu(){   cout << "Stu的析构函数" << endl;}//拷贝构造函数Stu(Stu& other):score(other.score),p1(other.p1){cout << "Stu的拷贝构造函数" << endl;}
};int main()
{float height = 175;float weight = 60;Per p("zhangsan",18,&height,&weight);Per p1 = p;Stu stu1(85.5,"lisi",18,&height,&weight);Stu stu2 = stu1;p.show();return 0;
}

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

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

相关文章

Golang使用消息队列(RabbitMQ)

最近在使用Golang做了一个网盘项目&#xff08;类似百度网盘&#xff09;&#xff0c;这个网盘项目有一个功能描述如下&#xff1a;用户会删除一个文件到垃圾回收站&#xff0c;回收站的文件有一个时间期限&#xff0c;比如24h&#xff0c;24h后数据库中记录和oss中文件会被删除…

C语言之扫雷游戏实现篇

目录 主函数test.c 菜单函数 选择循环 扫雷游戏实现分析 整体思路 问题1 问题2 问题3 问题4 游戏函数&#xff08;函数调用&#xff09; 创建游戏盘数组mine 创建游戏盘数组show 初始化游戏盘数组InitBoard 展示游戏盘DisplayBoard 游戏盘置雷SetMine 游戏…

设计模式之创建者模式

文章目录 一、介绍二、应用三、案例1. 麦当劳11随心配2. 代码演示3. 演示结果 四、优缺点五、送给读者 一、介绍 建造者模式(Builder Pattern)属于创建型设计模式&#xff0c;很多博客文章的对它的作用解释为用于将复杂对象的创建过程与其细节表示分离。但对于初学者来说&…

Pyqt5打开电脑摄像头进行拍照

目录 1、设计UI界面 2、设计逻辑代码&#xff0c;建立连接显示窗口 3、结果 1、设计UI界面 将ui界面转为py文件后获得的逻辑代码为&#xff1a;&#xff08;文件名为 Camera.py&#xff09; # -*- coding: utf-8 -*-# Form implementation generated from reading ui file …

无涯教程-PHP - File 函数

文件系统功能用于访问和操纵文件系统&#xff0c;PHP为您提供了操纵文件的所有功能。 运行时配置 这些功能的行为受php.ini中的设置影响。 NameDefaultChangeableChangelogallow_url_fopen"1"PHP_INI_ALLPHP_INI_ALL in PHP < 4.3.4. PHP_INI_SYSTEM in PHP &l…

windows上ffmpeg如何录制双屏幕中的一个屏幕上的视频

首先&#xff0c;如何在window上安装ffmpeg自己查找scoop安装ffmpeg. 如题&#xff1a; 如果你有两个屏幕&#xff0c;如何让ffmpeg来录制其中的一个屏幕的视频呢。 很简单&#xff0c;首先你要查看另外一个屏幕的分辨率&#xff1a; 第一步&#xff1a;进入系统中 第二步&am…

Python Opencv实践 - 图像直方图均衡化

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png", cv.IMREAD_COLOR) print(img.shape)#图像直方图计算 #cv.calcHist(images, channels, mask, histSize, ranges, hist, accumulate) #images&…

ModStartBlog v8.0.0 博客归档页面,部分组件升级

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.0 开源协议。 功能特性 丰富的模块市场&#xff0c;后台一键快速安装会…

C语言入门 Day_9 条件判断

目录 前言&#xff1a; 1.if判断 2.else判断 3.易错点 4.思维导图 前言&#xff1a; 我们知道比较运算和逻辑运算都会得到一个布尔型的数据&#xff0c;要么为真&#xff08;true&#xff09;&#xff0c;要么为假&#xff08;false&#xff09;。 今天我们来学习真和假在…

面试热题(复原ip地址)

有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址&#xff0c;但是 "0.011.255.24…

pyqt5-自定义停靠栏头部

import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class CustomDock(QDockWidget):def __init__(self, title: str, parentNone):super().__init__(title, parent)"""停靠栏的头部"""h_layout Q…

行式存储与列式存储

1.概述 数据处理大致可分为两大类&#xff0c;联机事务处理OLTP(on-line transaction processing) 和联机分析处理OLAP(on-line analytical processing)。 OLTP是传统关系型数据库的主要应用&#xff0c;用来执行一些基本的、日常的事务处理&#xff0c;比如数据库记录的增、删…

uniapp微信小程序点击右上角菜单分享功能权限配置

个人项目地址&#xff1a; SubTopH前端开发个人站 &#xff08;自己开发的前端功能和UI组件&#xff0c;一些有趣的小功能&#xff0c;感兴趣的伙伴可以访问&#xff0c;欢迎提出更好的想法&#xff0c;私信沟通&#xff0c;网站属于静态页面&#xff09; SubTopH前端开发个人站…

threejs贴图系列(一)canvas贴图

threejs不仅支持各种texture的导入生成贴图&#xff0c;还可以利用canvas绘制图片作为贴图。这就用到了CanvasTexture&#xff0c;它接受一个canas对象。只要我们绘制好canvas&#xff0c;就可以作为贴图了。这里我们利用一张图片来实现这个效果。 基础代码&#xff1a; impo…

开始MySQL探索——数据库概述

计算机语言 计算机语言概述 计算机语言&#xff08;Computer Language&#xff09;可以简单的理解为一种计算机和人都能识别的语言。 机器语言 汇编语言 高级语言 机器语言 汇编语言 高级语言 SQL语言基础 SQL的概述 SQL全称&#xff1a;Structured Query Language&…

无涯教程-PHP - preg_match()函数

preg_match() - 语法 int preg_match (string pattern, string string [, array pattern_array], [, int $flags [, int $offset]]]); preg_match()函数在字符串中搜索pattern&#xff0c;如果存在pattern&#xff0c;则返回true&#xff0c;否则返回false。 如果提供了可选…

Ansible 临时命令搭建安装仓库

创建一个名为/ansible/yum.sh 的 shell 脚本&#xff0c;该脚本将使用 Ansible 临时命令在各个受管节点上安装 yum 存储库. 存储库1&#xff1a; 存储库的名称为 EX294_BASE 描述为 EX294 base software 基础 URL 为 http://content/rhel8.0/x86_64/dvd/BaseOS GPG 签名检查为…

11_Redis经典五大类型源码及底层实现

Redis经典五大类型源码及底层实现 一、Redis数据类型的底层数据结构 SDS动态字符串双向链表压缩列表 zpilist哈希表 hashtable调表 skiplist整数集合 intset快速列表 quicklist紧凑列表 listpack 二、Redis源码地址 Github&#xff1a;https://github.com/redis/redis 三、…

java 项目运行时,后端控制台出现空指针异常---java.lang.NullPointerException

项目场景&#xff1a; 提示&#xff1a;这里简述项目背景&#xff1a; 场景如下&#xff1a; java 项目运行时&#xff0c;后端控制台出现如下图所示报错信息&#xff1a;— 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; java 项目运行时&#xff0c;后…

Elasticsearch 常见的简单查询

查看es中有哪些索引 请求方式&#xff1a;GET 请求地址&#xff1a;http://localhost:9200 /_cat/indices?v 参数&#xff1a;无 结果&#xff1a; 查看索引全部数据 请求方式&#xff1a;GET 请求地址&#xff1a;http://localhost:9200/index-2023-08/_search 参数&a…