C++类中的六大默认成员函数详解

在C++中,当你去创建一个类的时候,即便这个类是空类,也会自动生成下面6个默认成员函数,在本篇博客中,我将逐一分析下面6个默认成员函数。

构造函数

构造函数并不是去构造函数的函数,而是去对函数进行初始化的函数。构造函数的函数名与类名相同,当我们每次创建类对象的时候,就会自动调用构造函数。构造函数在对象的生命周期中只会调用1次。

class Date
{
public:
    //构造函数
	Date(int year = 2021, int month = 4, int day = 11)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

构造函数的几个特点

①函数名与类名相同

②无返回值

③对象实例化时编译器自动调用对应的构造函数

④构造函数可以重载

class Date
{
public:
    //构造函数的重载:
    //无参的构造函数
	Date()
	{}
    //需要传参的构造函数
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

⑤如果类中没有显式定义构造函数(就是自己没有去定义构造函数),那么编译器会自动生成一个无参的默认构造函数;

如果类中显式定义了构造函数,那么编译器将不再生成,而是去使用用户定义的构造函数。

⑥默认构造函数只能同时存在1个。默认构造函数分为以下3种:①无参的构造函数 ②全缺省的构造函数 ③编译器默认生成的构造函数

默认构造函数的共同特点是:不用传参就可以调用

class Date
{
public:
	//下面2种和 当你不写构造函数时编译器自动生成的默认构造函数只能同时存在1种
    //无参的
	Date()
	{
		_year = 2021;
		_month = 4;
		_day = 11;
	}
    //全缺省的
	Date(int year = 2021, int month = 4, int day = 11)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

⑦编译器生成的默认的构造函数,对内置类型(int, char, double...)不会做任何处理,但是会针对自定义类型的成员,调用它的构造函数去进行初始

构造函数调用的2种写法:

int main()
{
    //无参时
    Date d;
    //单个参数
	Date(1);
	Date d1 = 2;//这种写法会发生隐式类型转换
    //多个参数
    Date(2021, 4, 11);
    Date d2 = {2021, 4, 11};//C++11中才支持的写法
}

构造函数与初始化列表

初始化列表:以冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。

初始化列表有什么用?

初始化列表,顾名思义就是对对象进行初始化的,但是我们已经可以在构造函数体内进行初始化了(通过对成员变量进行赋值来进行初始化),为什么还需要初始化列表?

这是因为,有些类型的数据无法通过在构造函数体内进行赋值来进行初始化。这样的数据类型有下面3种:

  1. 引用成员变量
  2. const成员变量
  3. 自定义类型成员 (且它的类没有默认构造函数[即,它必须要进行传参])

上面的三种数据类型有一个共同的特点,它们都要求你在定义变量的时候进行赋值。

比如,引用成员变量,使用引用的时候必须进行初始化,否则语法就是错误的。

析构函数

析构函数的作用与构造函数相反,在对象的生命周期结束的时候会自动调用析构函数,完成类的一些资源清理的工作。

析构函数的特点

  • 析构函数名是在类名的前面加上~
  • 无参,无返回值
  • 一个类中有且只有1个析构函数。如果未显式定义,系统会自动生成默认的析构函数。(如果定义了,则采用显式定义的)
  • 对象生命周期结束时,C++编译系统会自动调用析构函数
  • 编译器生成的默认的析构函数,对内置类型(int, char, double...)不会做任何处理,但是会针对自定义类型的成员,会去调用它的析构函数

析构函数的一般使用情况:

一般使用在那些涉及到动态内存开辟空间的类中,因为这样的对象需要对其动态开辟的空间进行释放。

class Stack
{
public:
    //构造函数
	Stack(int n = 3)
	{
		_a = (int*)malloc(sizeof(int)*n);
		_size = 0;
		_capacity = n;
	}
    //析构函数
	~Stack()
	{
		free(_a);
		_size = _capacity = 0;
	}
private:
	int* _a;
	int _size;
	int _capacity;
};

拷贝构造函数

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象去创建新的对象时,编译器会自动调用拷贝构造函数。

拷贝构造函数的特点

  • 拷贝构造函数是构造函数的一个重载
  • 拷贝构造函数的参数只有1个,且必须使用引用传参,如果使用引用传值的形式会引发无限递归

拷贝构造函数的2种调用方法(完全等价的):

int main()
{
	Date d1(1);
	//拷贝构造函数
	Date d2(d1);  //1
	Date d3 = d1; //2

	return 0;
}

赋值运算符重载

在了解赋值运算符重载之前,我们需要先知道什么是运算符重载。

运算符重载

运算符重载是具有特殊函数名的函数。

函数名:关键字operator后面接需要重载的运算符符号(如:operator>)

函数原型:返回类型 operator操作符 (参数列表)

注意:

  • operator后面必须跟着的是操作符(这样是不可以的 operator@)
  • 重载操作符必须有一个类类型或者枚举类型的操作数
  • 用于内置类型的操作符,其含义无法改变。(比如内中的整型+,3+5这其中的+的意义不会改变)
  • this指针为限定的第一个形参,也就是this作为第一个操作数
  • .*、::、sizeof、?:、. 这5个操作符无法进行重载。

赋值运算符重载

class Date
{
public:
	Date(int year = 2021, int month = 4, int day = 11)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//赋值运算符重载
	Date& operator=(const Date& d)
	{
		_year = d._day;
		_month = d._month;
		_day = d._day;
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

注意:赋值运算符重载必须有返回值,如果没有返回值的话,无法解决 a = b = c 这种连续赋值的操作。

拷贝构造函数与赋值运算符重载

Date d1(1);
	Date d2(0);

	//赋值运算符重载
	d2 = d1;     //注意,只有2个操作数都是已经定义过的变量时,才会调用赋值运算符重载

	//拷贝构造函数
	Date d3(d1);

浅拷贝

浅拷贝是你在没有写拷贝构造函数和operator=时,编译器自动调用的默认成员函数。它的功能是将对象以字节的为单位拷贝过去。

取地址与const取地址操作符重载

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可(编译器默认的基本就够用了),只有特殊情况,才需要重载,比如想让别人获取到指定的内容。

class Date
{
public:
    //取地址操作符重载
	Date* operator&()
	{
		return this;
	}
    //const取地址操作符重载
	const Date* operator&()const
	{
		return this;
	}
private:
	int _year;
	int _month;
	int _day;
};

到此这篇关于C++类中的六大默认成员函数的文章就介绍到这了,更多相关C++类默认成员函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

class Date
{
public:
    //初始化列表
	Date(int year, int month, int day)
		:_year(year),
		 _month(month),
		 _day(day)
	{}

private:
	int _year;
	int _month;
	int _day;
};
(0)

相关推荐

  • c++中string类成员函数c_str()的用法

    1.string类成员函数c_str()的原型: const char *c_str()const;//返回一个以null终止的c字符串 2.c_str()函数返回一个指向正规c字符串的指针,内容和string类的本身对象是一样的,通过string类的c_str()函数能够把string对象转换成c中的字符串的样式; 3.操作c_str()函数的返回值时,只能使用c字符串的操作函数,如:strcpy()等函数.因为,string对象可能在使用后被析构函数释放掉,那么你所指向的内容就具有不确定性.

  • C++指向类成员函数的指针详细解析

    首先 函数指针是指向一组同类型的函数的指针:而类成员函数我们也可以相似的认为,它是指向同类中同一组类型的成员函数的指针,当然这里的成员函数更准确的讲应该是指非静态的成员函数.前者是直接指向函数地址的,而后者我们从字面上也可以知道 它肯定是跟类和对象有着关系的. 函数指针实例: 复制代码 代码如下: typedef int (*p)(int,int);//定义一个接受两个int型且返回int型变量的函数指针类型int func(int x,int y){ printf("func:x=%d,y=%

  • C++中与输入相关的istream类成员函数简介

    eof 函数 eof是end of file的缩写,表示"文件结束".从输入流读取数据,如果到达文件末尾(遇文件结束符),eof函数值为非零值(真),否则为0(假). [例] 逐个读入一行字符,将其中的非空格字符输出. #include <iostream> using namespace std; int main( ) { char c; while(!cin.eof( )) //eof( )为假表示未遇到文件结束符 if((c=cin.get( ))!=' ') //

  • C++中Operator类型强制转换成员函数解析

    类型转换操作符(type conversion operator)是一种特殊的类成员函数,它定义将类类型值转变为其他类型值的转换.转换操作符在类定义体内声明,在保留字 operator 之后跟着转换的目标类型.转换函数又称类型强制转换成员函数,它是类中的一个非静态成员函数.它的定义格式如下: 复制代码 代码如下: class <类型说明符1> { public: operator <类型说明符2>(); - } 这个转换函数定义了由<类型说明符1>到<类型说明符2

  • 实例解析C++中类的成员函数指针

    C语言的指针相当的灵活方便,但也相当容易出错.许多C语言初学者,甚至C语言老鸟都很容易栽倒在C语言的指针下.但不可否认的是,指针在C语言中的位置极其重要,也许可以偏激一点的来说:没有指针的C程序不是真正的C程序. 然而C++的指针却常常给我一种束手束脚的感觉.C++比C语言有更严格的静态类型,更加强调类型安全,强调编译时检查.因此,对于C语言中最容易错用的指针,更是不能放过:C++的指针被分成数据指针,数据成员指针,函数指针,成员函数指针,而且不能随便相互转换.而且这些指针的声明格式都不一样:

  • C++类静态成员与类静态成员函数详解

    当将类的某个数据成员声明为static时,该静态数据成员只能被定义一次,而且要被同类的所有对象共享.各个对象都拥有类中每一个普通数据成员的副本,但静态数据成员只有一个实例存在,与定义了多少类对象无关.静态方法就是与该类相关的,是类的一种行为,而不是与该类的实例对象相关. 静态数据成员的用途之一是统计有多少个对象实际存在. 静态数据成员不能在类中初始化,实际上类定义只是在描述对象的蓝图,在其中指定初值是不允许的.也不能在类的构造函数中初始化该成员,因为静态数据成员为类的各个对象共享,否则每次创建一

  • 详解C++编程中类的成员变量和成员函数的相关知识

    C++类的成员变量和成员函数 类是一种数据类型,它类似于普通的数据类型,但是又有别于普通的数据类型.类这种数据类型是一个包含成员变量和成员函数的一个集合. 类的成员变量和普通变量一样,也有数据类型和名称,占用固定长度的内存空间.但是,在定义类的时候不能对成员变量赋值,因为类只是一种数据类型,本身不占用内存空间,而变量的值则需要内存来存储. 类的成员函数也和普通函数一样,都有返回值和参数列表,它与一般函数的区别是:成员函数是一个类的成员,出现在类体中,它的作用范围由类来决定:而普通函数是独立的,作

  • C++子类父类成员函数的覆盖和隐藏实例详解

    C++子类父类成员函数的覆盖和隐藏实例详解 函数的覆盖 覆盖发生的条件: (1) 基类必须是虚函数(使用virtual 关键字来进行声明) (2)发生覆盖的两个函数分别位于派生类和基类 (3)函数名和参数列表必须完全相同 函数的隐藏 隐藏发生的条件: (1)子类和父类的函数名相同,参数列表可以不一样 看完下面的例子就明白了 #include "iostream" using namespace std; class CBase{ public: virtual void xfn(int

  • C++获取类的成员函数的函数指针详解及实例代码

    C++获取类的成员函数的函数指针详解 用一个实际代码来说明. class A { public: staticvoid staticmember(){cout<<"static"<<endl;} //static member void nonstatic(){cout<<"nonstatic"<<endl;} //nonstatic member virtualvoid virtualmember(){cout<

  • C++类中的六大默认成员函数详解

    在C++中,当你去创建一个类的时候,即便这个类是空类,也会自动生成下面6个默认成员函数,在本篇博客中,我将逐一分析下面6个默认成员函数. 构造函数 构造函数并不是去构造函数的函数,而是去对函数进行初始化的函数.构造函数的函数名与类名相同,当我们每次创建类对象的时候,就会自动调用构造函数.构造函数在对象的生命周期中只会调用1次. class Date { public: //构造函数 Date(int year = 2021, int month = 4, int day = 11) { _yea

  • C++中类的默认成员函数详解

    目录 一.构造函数 二.析构函数 三.拷贝构造函数 四.赋值函数(赋值运算符重载) 总结 C++中,对于任意一个类,都会为我们提供4个默认的成员函数(如果我们不显示的去声明)——构造函数.析构函数.拷贝构造函数.赋值函数.这些函数在特定的情况下会被自动调用,但自动调用并不意味着它们能像用户所期望的那样能实现特定的功能或者完成特定的任务,更多的时候需要我们自己实现这些函数的功能 A(); //默认的构造函数 ~A(); //析构函数 A(const A&); //默认的拷贝函数 A& ope

  • C++类中六个默认的成员函数详解

    浅谈 先来说一下"this指针": C++中通过引入this指针解决该问题,暨:C++编译器给每个"非静态的成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问,只不过所有的操作对用户是透明的,暨用户不需要来传递,编译器自动完成. 说了这么多其实编译器在生成程序时获取对象首地址的信息.然后将获取的对象的首地址存放在了寄存器中,成员函数的其它参数都是存放在栈中.而this指针参数则是

  • 详解C++中类的六大默认成员函数

    目录 一.类的默认成员函数 二.构造函数Date(形参列表) 1.构造函数的函数名和返回值 2.构造函数的调用 3.构造函数的重载 4.系统生成的默认构造函数 5.系统生成的默认构造函数的作用 6.可以在内置类型的成员变量的声明中给缺省值 7.初始化列表初始化 8.单参数构造(C++98).多参数构造(C++11) 三.析构函数~Date() 1.析构函数的函数名.参数和返回值 2.析构函数的特点 3.编译器生成的默认析构函数 四.拷贝构造Date(const Date& d) 五.赋值运算符重

  • C++类中const修饰的成员函数及日期类小练习

    目录 一.const修饰类的成员函数 1.问题引出: 2.问题分析 3.const修饰类的成员函数 二. 类的两个默认的&运算符重载 三. 日期类小练习 总结 一.const修饰类的成员函数 1.问题引出: 给出一段简单的代码 代码段: #include <iostream> using std::cin; using std::cout; using std::endl; class Date1 { public: Date1(int year = 2000) 类的全缺省构造函数(可

  • 基于Java中进制的转换函数详解

    十进制转成十六进制: Integer.toHexString(int i) 十进制转成八进制 Integer.toOctalString(int i) 十进制转成二进制 Integer.toBinaryString(int i) 十六进制转成十进制 Integer.valueOf("FFFF",16).toString() 八进制转成十进制 Integer.valueOf("876",8).toString() 二进制转十进制 Integer.valueOf(&qu

  • 对numpy中的transpose和swapaxes函数详解

    transpose() 这个函数如果括号内不带参数,就相当于转置,和.T效果一样,而今天主要来讲解其带参数. 我们看如下一个numpy的数组: `arr=np.arange(16).reshape((2,2,4)) arr= array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], [[ 8, 9, 10, 11], [12, 13, 14, 15]]]) ` 那么有: arr.transpose(2,1,0) array([[[ 0, 8], [ 4, 12]], [[ 1

  • 浅谈Python中的zip()与*zip()函数详解

    前言 1.实验环境: Python 3.6: 2.示例代码地址:下载示例: 3.本文中元素是指列表.元组.字典等集合类数据类型中的下一级项目(可能是单个元素或嵌套列表). zip(*iterables)函数详解 zip()函数的定义 从参数中的多个迭代器取元素组合成一个新的迭代器: 返回: 返回一个zip对象,其内部元素为元组:可以转化为列表或元组: 传入参数:元组.列表.字典等迭代器. zip()函数的用法 当zip()函数中只有一个参数时 zip(iterable)从iterable中依次取

  • 在C# 8中如何使用默认接口方法详解

    前言 C# 8 中新增了一个非常有趣的特性,叫做 默认接口方法 (又称虚拟扩展方法),这篇文章将会讨论 C# 8 中的默认接口方法以及如何使用. 在 C# 8 之前,接口不能包含方法定义,只能在接口中定义方法签名,还有一个就是接口的成员默认是 public 和 abstract , 在 C# 8 之前,接口不能包含字段,也不能包含private, protected, 或者 internal 的方法成员.如果你在接口中引入了一个新成员,默认情况下你必须更新实现该接口的所有子类. 在 C# 8 中

  • C++类的静态成员变量与静态成员函数详解

    目录 1.类的静态成员变量 2.静态成员函数 总结 1.类的静态成员变量 C++类的静态成员变量主要有以下特性: 1.静态成员变量需要类内定义,类外初始化 2.静态成员变量不依赖于类,静态成员变量属于全局区,不属于类的空间. 3.静态成员变量通过类名访问,也可以通过对象访问,同一类的不同对象,静态成员共享同一份数据 下面通过代码验证以上三种说法: #include <iostream> using namespace std; class Base{ public: static int va

随机推荐