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.构造函数

作用:对象所在的内存空间做初始化 、给对象赋资源

特点

  1. 可以重载 :可以根据实际需要进行缺省的、多参重载
  2. 不依赖对象:对象无法调用构造函数,只能在对象定义点被调用
//成员函数类外实现,需在函数名前指定作用域,否则编译器会认为在定义一个普通的函数
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.析构函数

作用:释放对象所占的其他资源。

特点

  1. 不可重载 : 对象销毁时会调用析构函数,并释放空间。
  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.赋值运算符的重载函数

作用:拿一个已存在的对象给相同类型的已存在对象赋值

实现步骤

  1. 自赋值判断
  2. 释放旧资源
  3. 生成新资源
  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++类中隐藏的六个默认函数的更多相关文章

  1. 孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘

    孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天发现了python的类中隐藏着一些特殊的私有方法. 这些私有方法不管我 ...

  2. C++11 类的六个默认函数及其使用

    六个默认函数: 构造函数(construct) 析构函数(destruct) 复制构造函数(copy construct) 赋值(assign) 移动构造函数(move construct) 移动赋值 ...

  3. C++类中的静态成员变量与静态成员函数

    最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下. 静态成员的概念: 静态 ...

  4. C++ 类中的静态成员变量,静态成员函数

    //类中的静态成员变量,静态成员函数 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* ...

  5. C++类中的静态成员变量和静态成员函数的作用

    数据成员可以分为静态变量.非静态变量两种. 静态成员:静态类中的成员加入static 修饰符,即是静态成员,可以使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配 ...

  6. C++类中的静态成员变量与静态成员函数的使用

    代码: #include <iostream> #include <string> #include <cstdio> using namespace std; c ...

  7. C# 类中隐藏基类方法和Partial

    今天对于.NET开发人员来说最开心的事情莫过于微软搞开源了,这觉得是给搞.NET开发的长脸.虽然我是一个初学者,这无疑给我极大的学习动力.Fighting!!! 当一个类从父类继承了一个成员时,也就继 ...

  8. QWidget类中默认是忽略inputMethodEvent事件(要获取输入的内容就必须使用这个事件)

    因为项目的需要以及主管的要求,准备将工程移植到Qt中,这样就可以比较容易的实现跨平台了.因为之前工程是在windows下开发的,第一个平台又是mobile所以除了底层框架之外其他的都是使用的windo ...

  9. C++类的默认函数

    在C++中,一个类有八个默认函数: 默认构造函数: 默认拷贝构造函数: 默认析构函数: 默认重载赋值运算符函数: 默认重载取址运算符函数: 默认重载取址运算符const函数: 默认移动构造函数(C++ ...

随机推荐

  1. Oracle之SQL的简单查询

    查询结构 --SQL语句的执行原理以及语法结构: /* SELECT * | 列名1[,列名2...] | 表达式 FROM 表名 [表的别名] WHERE 分组前的筛选条件 GROUP BY 列名1 ...

  2. 关于WinForm布局那些事情

    最近项目中,需要用WinForm做一些简单的功能,给第三方作为测试用.本来想着简单的拖几个控件,布局一下就了事了的.但是因为第三方是个大客户,需要展示出我们的技术水平.遂好好的研究了一下WinForm ...

  3. c# 表格控件SourceGrid使用总结

    网上SourceGrid相关的资料很少,使用过程中做了下记录,以便日后查用 1:初始化 this.grid = new SourceGrid.Grid(); this.grid.Size = new ...

  4. (第一章第一部分)TensorFlow框架介绍

    接下来会更新一系列博客,介绍TensorFlow的入门使用,尽可能详细. 本文概述: 说明TensorFlow的数据流图结构 1.数据流图介绍  TensorFlow是一个采用数据流图(data fl ...

  5. VirtualBox虚拟机--桥接模式

    问题概述:VirtualBox虚拟机设置桥接模式,与宿主机互相ping通. 注:如果按照以下方式设置了还是ping不通,查看虚拟机防火墙是否已关. 公司电脑拿去维修了,在自己家里电脑上部署项目开发环境 ...

  6. Python自动化 unittest生成测试报告(HTMLTestRunner)03

    批量执行完用例后,生成的测试报告是文本形式的,不够直观,为了更好的展示测试报告,最好是生成HTML格式的. unittest里面是不能生成html格式报告的,需要导入一个第三方的模块:HTMLTest ...

  7. 调用Visual Studio的cl.exe编译C/C++程序

    @ 目录 调用Visual Studio的cl.exe编译C/C++程序 前言 1.查看VS的路径 2.添加环境变量 3.查看设置是否生效 4.配置Notepad++ 调用Visual Studio的 ...

  8. 如何在Room框架下注册onUpgrade回调及自定义DatabaseErrorHandler

      在 Android 中,Room 为 SQLite 提供了高效稳定的抽象层,简化开发流程.RoomDatabase.java 是初始化数据库的重要构建组件,通过它我们可以添加RoomDatabas ...

  9. 一比一还原axios源码(三)—— 错误处理

    前面的章节我们已经可以正确的处理正确的请求,并且通过处理header.body,以及加入了promise,让我们的代码更像axios了.这一章我们一起来处理ajax请求中的错误. 一.错误处理 首先我 ...

  10. Three.js 火焰效果实现艾尔登法环动态logo 🔥

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 <艾尔登法环>是最近比较火的一款游戏,观察可以发现它的 Log ...