C++ 类 、构造、 析构、 重载 、单例模式 学习笔记及练习
1、是一种特殊的构造函数,就是用一个已有的对象去构造其同类的副本对象,即对象克隆。
class 类名
{
类名(类名& that)
{
对类成员挨个赋值
...
}
}
练习:定义一个学生类,实现它的拷贝构造函数。
Student stu2 = stu1; // 调用拷贝构造
stu2 = stu1; // 调用赋值构造
2、编译器会默认生成一个拷贝构造函数
编译生成的拷贝构造函数默认会逐字节复制类中的每一个成员。
如果在类A中有类B成员,会在类A的拷贝构造中自动调用类B的拷贝构造。
3、程序员可以自定义拷贝构造来取代默认的拷贝构造。
a、拷贝构造只能有一个,不能重载。
b、一旦程序员自定义的拷贝构造,编译器就不再生成。
c、在自定义的拷贝构造中能通过编码来实现成员的复制。
4、一般情况下编译器生成的拷贝构造完全够用,不要轻易自定义构造。
a、对象与对象赋值
b、用对象与函数传参
c、用对象当作返回值
class Student
{
char* name;
char sex;
short age;
};
Student stu1;
Student stu2 = stu1;
stu.name = new char[];
此类在使用过程中偶尔会发生段错误、数据丢失、内存泄漏,如何改进此类。
1、是一种成员的初始化方式,在构造函数的大括号体前使用小括号对类的成员进行初始化的一种方式。
class 类名
{
类名(参数列表):成员1(参数1),成员2(参数2)
{ }
}
a、参数列表可以解决构造函数的参数与成员重名的问题。
b、参数列表会行于构造函数执行。
2、如果类成员是数组,可以使用{}进行初始化。
3、如果有成员是类,可以在初始化列表中显示调用构造函数。
4、如果成员中有const成员、引用成员,必须使用初始化列表。
5、类成员的构造顺序与初始化列表无关,而是与成员定义的顺序有关。
1、相同类型的对象各自拥有独立的成员实例,彼此双共享一份成员函数,成员函数是如何知道谁在调用它。
2、为了让成员函数知道是哪个对象在调用,并准确访问到对象的成员,编译器会自动为每个成员函数添加一个看不到的参数,这个参数就是指向调用对象的指针(this)。
3、类中的所有成员函数都有this指针,包括构造、析构、拷贝构造等。
只是构造中this指向的是正在被创建的对象。
4、this指针默认情况下都是隐藏的(在成员函数中访问成员变量时自动就加上了),但也可以显示使用。
5、使用情况使用this
a、区分成员变量与参数
b、把对象当作返回值与其它对象进行交互。
1、创建对象时添加const关键字,这个对象就不可再修改,就有了常属性,就意味着整个对象中的所有东西都不能修改。
2、常对象不能调用普通成员函数,调用成员函数就相当于把对象的this指针给了它,就会有被修改的风险。
3、函数体前加const关键的叫常函数,常对象只能调用常函数,普通对象也可以调用常函数。
常函数就相当于对this指针添加了cosnt属性。
4、常函数与'非'常函数会形成重载不会冲突。
5、如果有成员确实需要修改,它又需要被const修饰,可以对成员添加一个关键字mutable,这样即使常对象调用了常函数依然可以修改成员。
1、当对象被销毁时自动调用的函数叫析构函数,对象的整个生命周期中只能被调用一次,它是对象被销毁前的最后一个执行的动作。
class 类名
{
// 不能重载、只能有一个
// 没有返回值、没有参数
~类名(void)
{ }
}
1、赋值构造就是一个对象给另一个对象赋值的时候调用的函数。
stu2 = stu1; // 赋值构造
Student stu2 = stu1;// 拷贝构造
void func(Student stu);// 拷贝构造
func(stu1);
Student func(void) // 拷贝构造
{
return *this;
}
Student stu = func()
void operator = (Student& that)
{
}
// 可以与其它对象进行交互
Student& operator = (Student& that)
{
}
拷贝构造:使用对象A去创建出对象B(调用时对象B还末生成)。
赋值构造:对象A与对象B都已经构造完成,此时B = A;
如果对象中有常成员拷贝构造可以成功调用,但赋值构造不行。
5、一般情况下默认的赋值构造基本够用的,除非有成员是指针,指向了额外的内存空间,这种情况下才需要自定义拷贝构造、赋值构造。
6、自定义赋值构造
a、确定赋值构造的格式
b、防止自赋值
int num = 1;
num = num;
c、释放旧资源
d、分配新的资源
e、拷贝新内容
//f、代码利用(显式调用拷贝构造)
七、静态成员与静态成员函数
1、类成员被static修饰后,就会存储在bss段(此段是由编译存放的而且大小固定),在程序中动态的创建对象时它的静态成员就无法创建,所有的类对象共享一个静态成员。
2、静态成员只能在类中声明不能类中定义(必须在类外定义)。
类型 类名::静态成员名;
3、静态成员就是声明在类中的全局变量,在任何位置都可以使用
类名::静态成员名进行访问。
4、静态成员函数,类中的成员函数被static修饰后就变成了静态成员函数,所有对象共享一份静态成员函数。
5、静态成员函数不会传递this指针,也就不能访问成员变量。
不通过对象也能调用静态成员函数
类名::静态成员函数(参数)
八、单例模式
1、只能创建出一个对象的类,这种类就叫作单例类,这种模式就叫作单例模式。
2、为什么需要单例模式,是为了提高安全性和稳定性的技巧。
只允许存在唯一对象实例
单例模式的商业应用:
网站计数器
日志管理系统
连接池、线程池、内存池
3、获取对象实例的专门方法
a、全局变量的定义不受控制,能防君子不能防小人
b、专门方法是类的一部分,"我是类型我做主",
借助类禁止在外部创建对象,仅在类内部提供获取对象的接口。
4、如何实现单例模式
a、禁止在类外部创建实例,私有所有的构造函数 private
b、类自己维护其唯一实例,
静态成员变量 static 类名 instance;
静态成员指针 static 类名* instance;
c、提供访问该实例的方法,静态成员函数getInstance()
不管是否需要对象都已经创建好了。
优点:效率高、速度快、稳定。
缺点:浪费资源,不管需不需要对象都已经创建好;
当首次使用获取对象时才会真正创建出对象。
优点:节约资源
缺点:效率低,速度慢,不安全(多线程情况下)。
在C++中,编译器有能力把一个由数据、对象和操作符共同组成的表达式,解释为对一个全局或成员函数的调用。
该全局或成员函数被称为操作符函数,通过重定义操作符函数,可以实现针对自定义类型的运算法则,并使之与内置类型一样参与各种表达式。
成员函数
形如L#R双目操作符表达式,将被编译器解释为 L.operator#(R)
a-b+c == a.operator-(b).operator+(c)
全局函数
形如L#R的双目操作符表达式,将被编译器解释为 ::operator#(L,R)
a-(b+c) == ::operator-(a,::operator+(b,c))
成员函数
形如#O或O#的单目操作表达式,将被编译器解释为 O.operator#(),唯一的操作数是调用对象。
全局函数
形如#O或O#的单目操作表达式,将被编译器解释为 ::operator#(O),唯一的操作数是调用对象。
成员函数
Point operator /+-*%|^& (Point& that)
{
Point t; // 会调用无参构造
t.x = x / that.x;
t.y = y / that.y;
return t; // 不能返回局部对象的引用,否则会出现悬空引用
}
注意:原对象的值不变,要产生一个临时的对象
bool operator > < >= <= == != || && (Point& that)
{ }
Point& operator += -= *= /= (Point& that)
{ return *this;
}
注意:运算符的重载要符合情理。
可能会访问到参数的私有成员:
1、把成员变成公开,但会破坏类的封闭性。
2、把全局函数声明为友元(友元不是成员),
3、不能在友元函数中直接访问成员变量。
Point operator + (Point& a,Point& b)
{
Point t(a.x+b.x,a.y+b.y);
return t;
}
成员函数:
前++/--
Point& operator ++/-- (void)
{
}
后++/--
Point operator ++/-- (int)
{
}
全局函数:
前++/--
Point& operator ++/-- (Point&)
{
}
后++/--
Point operator ++/-- (Point&,int)
{
}
输入、输出运算符不能重载为成员函数,只能是友元。
ostream& operator << (ostream& os,Point& p)
{
}
istream& operator >> (istream& is,Point& p)
{
}
[] 下标运算符,可以把对象当作数组来使用。
() 函数运算符,可以把对象当作函数来使用。
-> 成员访问运算符,可以把对象当作指针来使用。
* 解引用运算符,可以把对象当作指针来使用。
new/delete 也可以进行重载,但不建议使用。
new会自动调用重载的new函数再构造函数。
delete会先调用析构再调用重载的delete函数。
常考的运算符重载:前++/--,后++/--
1、不能重载的运算符
:: 作用域限定符
. 成员访问运算
.* 成员指针解引用
?: 三目运算符
sizeof 字节长度运算符
typeid 类型信息操作符
2、运算符的重载改变不了运算符的优先级
3、无法改变运算符的操作个数
4、无法发明新的运算符
5、重载运算符要注意运算符的一致性
不要改变运算符默认的运算规则
6、运算符的重载是为了方便使用、增强可读,不应该成功卖弄的工具。
C++ 类 、构造、 析构、 重载 、单例模式 学习笔记及练习的更多相关文章
- 第2课第1节_Java面向对象编程_类的引入_P【学习笔记】
摘要:韦东山android视频学习笔记 1. 面向对象编程的引入,我们先写一个简单的程序输出张三,李四的名字.代码如下,假如,现在我们要在名字前面添加籍贯广东,那样岂不是每个printf语句都得修改添 ...
- java单例模式学习笔记
最近一直在学习多线程,在学习过程中遇到了关于单例模式的多线程安全问题,内容如下: 一:首先什么是单例模式 单例模式具有的三要点: 一个类只能有一个实例: 必须是由它自己创建的这个实例: 它必须自行向外 ...
- 《C++ Primer Plus》10.3 类的构造函数和析构函数 学习笔记
10.3.1 声明和定义构造函数构造函数原型:// constructor prototype with some default argumentsStock(const string &c ...
- C++类构造析构调用顺序训练(复习专用)
//对象做函数参数 //1 研究拷贝构造 //2 研究构造函数,析构函数的调用顺序 //总结 构造和析构的调用顺序 #include "iostream" using namesp ...
- No2_5.类的高级特性_Java学习笔记_抽象类和成员内部类
一.抽象类1.所谓抽象类,只声明方法的存在而不去实现它的类:2.抽象类不能被实例化,即不能实现其对象:3.abstract class 类名{ 类体 }4.包含一个或多个抽象方法的类必须声明成抽象类: ...
- java 单例模式学习笔记
1.单例模式概述 单例模式就是确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供. 2.优缺点 优点:在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模 ...
- 《C++ Primer Plus》第16章 string类和标准模板库 学习笔记
C++提供了一组功能强大的库,这些库提供了很多常见编程问题的解决方案以及简化其他问题的工具string类为将字符串作为对象来处理提供了一种方便的方法.string类提供了自动内存管理动能以及众多处理字 ...
- 《C++ Primer Plus》第12章 类和动态内存分配 学习笔记
本章介绍了定义和使用类的许多重要方面.其中的一些方面是非常微妙甚至很难理解的概念.如果其中的某些概念对于您来说过于复杂,也不用害怕——这些问题对于大多数C++的初学者来说都是很难的.通常,对于诸如复制 ...
- 0035 Java学习笔记-注解
什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...
随机推荐
- Linux-(tar,gzip,df,du)
tar命令 首先要弄清两个概念:打包和压缩.打包是指将一大堆文件或目录变成一个总的文件:压缩则是将一个大的文件通过一些压缩算法变成一个小文件. 为什么要区分这两个概念呢?这源于Linux中很多压缩程序 ...
- MySQL查询时区分大小写
在创建MySQL数据库时,下面这些参数可供我们选择:*_bin: 表示的是binary case sensitive collation,也就是说是区分大小写的 *_cs: case sensitiv ...
- JS的作用域和声明提前
首先介绍下Javascript的函数作用域的概念,然后了解下什么是作用域和声明提前,最后通过一个例子剖析Javascript的作用域链. 1.变量的作用域 稍微有些编程背景的都知道,变量的作用域分为两 ...
- echarts 雷达图的个性化设置
echarts 雷达图的个性化设置 function test() { let myChart = echarts.init(document.getElementById('levelImage') ...
- 一个在linux环境执行io操作的bug
今天项目有了一个奇葩的要求...是什么呢 后台上传了视频后,解析其中的时长,和预览图,并拼接在一起,然而,之东西并不是太麻烦,很快写好了,在本地测试后也没有问题,嗯,发布到测试环境后,一个jar包报错 ...
- mysql和SQLAlchemy
mysql和SQLAlchemy 一.MySQL分组查询 1.1 MySQL对数据表进行分组查询(GROUP BY) 1.GROUP BY基本语法格式: GROUP BY关键字可以将查询结果按照某个字 ...
- 用于深拷贝的扩展方法 C#
using System.Runtime.Serialization.Formatters.Binary; using System.IO; public static class Tool { pu ...
- [日常] nginx与HTTP cache
去年的事,随便记记 =============================================================2017年12月11日 记录: nginx缓存:ngx_h ...
- [转] PHP读取HTTP接口如何处理超时
原文地址:https://www.jianshu.com/p/446ea7aaea86 最近在工作中遇到一个读取 HTTP 接口慢的问题(使用的是 PHP 服务器端语言),所以想谈谈服务器端读取外部资 ...
- 大话JVM(一):垃圾收集算法
系列介绍|本系列主要是记录学习jvm过程中觉得重要的内容,方便以后复习 在说垃圾收集算法之前,先要说一下垃圾收集,从大的讲,垃圾收集需要考虑三件事情: 1.哪些内存需要回收 2.什么时候回收 3.如 ...