C++类中隐藏的六个默认函数
Test类中隐藏的六个默认的函数
class Test
{
public:
//默认的构造函数
Test();
//析构函数
~Test();
//拷贝构造函数
Test(const Test &t);
//赋值函数
Test& operator=(const Test &x);
//一般对象取地址函数
Test* operator&();
//常对象取地址函数
const Test* operator&()const;
private:
int data;
//int *data;
};
1.构造函数
作用:对象所在的内存空间做初始化 、给对象赋资源
特点:
- 可以重载 :可以根据实际需要进行缺省的、多参重载
- 不依赖对象:对象无法调用构造函数,只能在对象定义点被调用
//成员函数类外实现,需在函数名前指定作用域,否则编译器会认为在定义一个普通的函数
Test::Test() //类中默认的构造函数
{
}
//此外,构造函数可以支持重载,我们可以根据需要自己写一些构造函数
//需要注意的是,如果我们自己写了构造函数,那么编译器就不会提供默认的构造函数了
Test::Test(int d = 0 ) //缺省的构造函数
{
data = d;
}
Test::Test(int d = 0 ):data(d) //缺省的构造函数,用初始化器的方式初始化
{
}
两者初始化的区别在于,初始化器是真正意义上的初始化,它告诉编译器在实例化对象的时候以何种方式对成员赋值,而在前者的赋值规则写在了构造函数内部,是在已经生成了成员变量之后再进行的赋值操作。
初始化器实例:比如以下操作,成员变量定义为const类型,在C语言中const类型是一个常变量在定义的时候可以不初始化,而在C++中规定const类型为一个常量,定义时必须初始化。所以以下操作只能使用初始化器的方式初始化。
class Test
{
public:
Test(int a)
:ma(a)
{
//ma = a;
}
private:
const int ma;
};
此外,如果有多个成员变量需要使用初始化器的方式初始化,需要注意一点细节,初始化的顺序与成员变量的定义顺序相关。如以下程序,可以写成Test(int a):ma(mb), mb(a){}或Test(int a):mb(a),ma(mb){}因为成员变量的定义顺序为int mb; int ma;,也就是说赋值顺序与初始化器无关,只与成员变量被定义的顺序有关。
class Test
{
public:
Test(int a):ma(mb), mb(a) //mb先被定义出来,先给mb赋值,再给ma赋值
{
}
Test(int a):mb(ma), ma(a) //error mb先定义出来,此时ma还未被定义,所以mb(ma)赋值无效,最终结果为,mb无效值,ma=a
{
}
void Show()
{
std::cout << "ma: " << ma << std::endl;
std::cout << "mb: " << mb << std::endl;
}
private:
int mb;
int ma;
};
2.析构函数
作用:释放对象所占的其他资源。
特点:
- 不可重载 : 对象销毁时会调用析构函数,并释放空间。
- 依赖对象:可用手动调用,但是不建议,因为对象销毁时会自动调用,如果手动调用可能会引起内存空间的重复析构导致程序崩溃
//默认的析构函数
Test::~Test()
{ //没有额外的资源,什么都不写
}
//如果程序中有额外的空间需要释放
class Test
{
public:
//构造函数
Test()
{
data = new int; //data指向一块堆区内存
}
//析构函数
~Test();
private:
int* data;
};
//析构函数
Test::~Test()
{
delete data; //把额外空间的释放写进析构函数
}
3.拷贝构造函数
作用:拿一个已存在的对象来生成相同类型的新对象
注意:类中提供的拷贝构造函数为一个浅拷贝类型,即如果成员变量中含有指针类型,它在进行拷贝构造的时候不会进行额外空间的开辟,最终会造成函数析构时的错误。
class Test
{
public:
//构造函数
Test()
{
data = new int; //data指向一块堆区内存
}
//拷贝构造函数
Test(const Test &t); //一定要传引用,否则在开辟形参的过程中会递归的调用拷贝构造函数来构造形参,而函数始终无法执行
private:
int* data;
};
//默认的拷贝构造函数
Test::Test(const Test &t)
{
data = t.data; //浅拷贝,只把现有的成员变量进行拷贝,没有对堆区内存进行拷贝,使多个对象的data指向了同一片堆区空间,在对象销毁时会造成空间的重复释放引发程序崩溃。
}
//拷贝构造函数
Test::Test(const Test &t)
{
data = new int; //如果是字符类型data = new char[strlen(t.data) + 1];
strcpy_s(data,sizeof(int), t.data);
}
4.赋值运算符的重载函数
作用:拿一个已存在的对象给相同类型的已存在对象赋值
实现步骤
- 自赋值判断
- 释放旧资源
- 生成新资源
- 赋值
class Test
{
public:
//构造函数
Test()
{
data = new int; //data指向一块堆区内存
}
//赋值函数
Test& operator=(const Test &x); //以自身类类型的引用的方式返回
private:
int* data;
};
//默认的赋值函数(浅拷贝)
Test& operator=(const Test &x)
{
if(this!=&x) //自赋值判断
{
data=x.data; //浅拷贝
}
return *this; //返回自身类类型的引用
}
//赋值函数(深拷贝)
Test& operator=(const Test &x)
{
if(this!=&x) //自赋值判断
{
delete[] data; //释放原资源,比如 a = 4, b = 5, a = b此时a放弃原先的资源 4
data = new int;
strcpy_s(data,sizeof(int), t.data);
}
return *this; //返回自身类类型的引用
}
5.一般对象取地址函数
//一般对象取地址函数
Test::Test* operator&()
{
return this;
}
6.常对象取地址函数
//常对象取地址函数
const Test::Test* operator&()const
{
return this;
}
C++类中隐藏的六个默认函数的更多相关文章
- 孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘
孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天发现了python的类中隐藏着一些特殊的私有方法. 这些私有方法不管我 ...
- C++11 类的六个默认函数及其使用
六个默认函数: 构造函数(construct) 析构函数(destruct) 复制构造函数(copy construct) 赋值(assign) 移动构造函数(move construct) 移动赋值 ...
- C++类中的静态成员变量与静态成员函数
最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下. 静态成员的概念: 静态 ...
- C++ 类中的静态成员变量,静态成员函数
//类中的静态成员变量,静态成员函数 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* ...
- C++类中的静态成员变量和静态成员函数的作用
数据成员可以分为静态变量.非静态变量两种. 静态成员:静态类中的成员加入static 修饰符,即是静态成员,可以使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配 ...
- C++类中的静态成员变量与静态成员函数的使用
代码: #include <iostream> #include <string> #include <cstdio> using namespace std; c ...
- C# 类中隐藏基类方法和Partial
今天对于.NET开发人员来说最开心的事情莫过于微软搞开源了,这觉得是给搞.NET开发的长脸.虽然我是一个初学者,这无疑给我极大的学习动力.Fighting!!! 当一个类从父类继承了一个成员时,也就继 ...
- QWidget类中默认是忽略inputMethodEvent事件(要获取输入的内容就必须使用这个事件)
因为项目的需要以及主管的要求,准备将工程移植到Qt中,这样就可以比较容易的实现跨平台了.因为之前工程是在windows下开发的,第一个平台又是mobile所以除了底层框架之外其他的都是使用的windo ...
- C++类的默认函数
在C++中,一个类有八个默认函数: 默认构造函数: 默认拷贝构造函数: 默认析构函数: 默认重载赋值运算符函数: 默认重载取址运算符函数: 默认重载取址运算符const函数: 默认移动构造函数(C++ ...
随机推荐
- Specified cast is not valid(C#) 引发的思考(装箱,拆箱本质)
没有很华丽的语言,直接拿代码说事情把. 这段代码,会报错吗? 结论:当然不会 这段代码会报错了.原因是为啥? 这里面的水比较深.也要提醒各位写代码的适合要引起注意.异常:System.Invalid ...
- Java:Path与Paths
0.说明 用于读Path操作的接口(Path)与实现类(Paths) 1.模块:java.nio.file.Path.java.nio.file.Paths 2.方法 2.1.Paths 只有两个静态 ...
- SQL Server用SPLIT函数分割字符串
declare @str varchar(100),@sql varchar(1000)set @str='1,2,3,4,5,6,7,8,9,10'set @sql='select Value= ...
- laravel7 数据库数据导出至 xlsx
网址参考: https://learnku.com/articles/32391 1:安装excel插件 安装方式 composer require maatwebsite/excel 2:excel ...
- LGP3449题解
其实每个串都不是回文串也能做的说... 题意:给定 \(n\) 个互不相同的串,两两拼接一共能够拼出 \(n^2\) 个串,问这 \(n^2\) 个串中有几个回文串. 首先假设拼接出来的串是 \(AB ...
- 朴素版Dijkstra
我们之前介绍的求最短路问题,我们通常会考虑到用BFS算法计算,这里我们将这样对于求最短路问题用不同的算法进行分类: 思路介绍:Dijkstra算法的思路究竟是怎么样的,我们这里先介绍一下朴素版Dijk ...
- Mybatis执行流程浅析
从三个主要的对象SqlSessionFactoryBuilder->SqlSessionFactory->SqlSession说起 inputStream = Resources.getR ...
- Linux移植实际操作一
@ 目录 *前言 目前看了很多关于"Linux移植"的的各种教程.书籍,看完发现不过是对已有板子.已有驱动进行启用.禁用.参数修改.只能叫做"Linux配置". ...
- Python之VSCode
在学习Python的过程中,一直没有找到比较趁手的第三方编辑器,用的最多的还是Python自带的编辑器.由于本人用惯了宇宙第一IDE(Visual Studio),所以当Visual Studio C ...
- 4月28日 python学习总结 线程与协程
一. 异步与回调机制 问题: 1.任务的返回值不能得到及时的处理,必须等到所有任务都运行完毕才能统一进行处理 2.解析的过程是串行执行的,如果解析一次需要花费2s,解析9次则需要花费18s 解决一: ...