重生之我要学C++第五天

这篇具有很好参考价值的文章主要介绍了重生之我要学C++第五天。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这篇文章主要内容是构造函数的初始化列表以及运算符重载在顺序表中的简单应用,运算符重载实现自定义类型的流插入流提取。希望对大家有所帮助,点赞+收藏+评论,支持一下吧!

目录

构造函数进阶理解

 1.内置类型成员在参数列表中的定义

2.自定义类型成员在参数列表中的定义

3.初始化列表解决的三大问题

(1)类中的引用成员变量

​编辑

(2)const成员变量

(3)自定义类型成员没有默认构造函数时的问题

运算符重载的应用

(1)顺序表中的运算符重载

(2)自定义类型的流插入流提取


构造函数进阶理解

在上一篇文章中,我们已经了解过构造函数的作用:初始化对象

注意,构造函数仅仅说是初始化对象,那么在初始化前一定有为对象分配内存空间,即成员变量的定义。什么时候完成成员变量的定义呢?那就是构造函数内部的初始化列表。

下面给出初始化列表的语法规则:

初始化列表:以一个 冒号开始 ,接着是一个以 逗号分隔的数据成员列表 ,每个 " 成员变量 " 后面跟一个放在括号中的初始值或表达式。初始化列表是成员变量定义(分配内存空间)的地方,包括自定义类型,内置类型成员。
class A//类A
{
public:
    A()
    {
        cout<<"调用A的默认构造 A()"<<endl;
        _a=i;
    }
    A(int i)
	{
		cout << "调用A的带参构造 A(int)" << endl;
		_a = i;
	}
private:
    int _a;
};
class Date//类Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)//构造函数
		:_year(year),//构造函数的初始化列表(为成员变量分配空间)
		_month(month),
		_day(day),
        a()
	{
		//构造函数函数体
	}
private:
                //成员变量的声明
	int _year;//内置类型成员
	int _month;
	int _day;
    A a;//自定义类型成员
};

初始化列表是构造函数不可缺少的,就算不手动写编译器也会默认添加。默认添加的初始化列表为内置类型分配空间,但不指定值(随机值)。对自定义类型成员会调用自定义类型的默认构造函数。

public:
	Date(int year = 1, int month = 1, int day = 1)//构造函数
		/*:_year(),    //编译器默认添加,会为成员分配内存空间,是随机值
		_month(),
		_day(),
        a()*/            //对自定义类型会调用自定义类型的默认构造函数
	{
		
	}

 1.内置类型成员在参数列表中的定义

此时上面的构造函数未手动添加初始化列表,这时创建一个对象

Date d1;
d1.Print();

打印d1的内置类型成员变量。

重生之我要学C++第五天,重生之C++启程,c++,开发语言

 是随机值,因为默认初始化列表只为内置类型成员变量分配了内存空间,并没有给成员变量赋值

此时赋值操作既可以在手动添加的初始化列表中完成,也可以在函数体中完成赋值。

(1).手动添加的初始化列表中完成赋值

Date(int year = 1, int month = 1, int day = 1)//构造函数
		:_year(year),
		_month(month),
		_day(day)
	{
		
	}
Date d1;
d1.Print();

运行结果:

重生之我要学C++第五天,重生之C++启程,c++,开发语言

 (2).函数体内完成赋值

public:
	Date(int year = 1, int month = 1, int day = 1)//构造函数
	/*	:_year(),
		_month(),
		_day()*/  //默认参数列表
	{
		_year = year;
		_month = month;
		_day = day;
	}
Date d1;
d1.Print();

运行结果:

重生之我要学C++第五天,重生之C++启程,c++,开发语言

总结:内置类型成员变量的定义(分配内存空间)只能在初始化列表中一次性完成,不管写不写都会有这个过程,手动写可以顺便在定义时赋值。不写编译器的默认参数列表会将成员变量定义为随机值,之后再函数体中再次赋想要的值。 

2.自定义类型成员在参数列表中的定义

当我们不手动添加初始化列表,默认的初始化列表会调用自定义类型成员的默认构造函数

例如:当构造函数是这样时

Date(int year = 1, int month = 1, int day = 1)//构造函数
		//:_year(),//默认初始化列表
		//_month(),
		//_day(),
		//a()  默认构造函数的调用
	{
		//构造函数函数体
	}
Date d1;

运行结果: 

 重生之我要学C++第五天,重生之C++启程,c++,开发语言

 当我们手动写初始化列表时,就可以选择性的调用自定义类型的构造函数,可以是带参的,也可以是默认构造函数。

	Date(int year = 1, int month = 1, int day = 1)//构造函数
		:_year(year),//默认初始化列表
		_month(month),
		_day(day),
		a(2) //选择调用带参构造函数

此时

	Date d1;

运行结果 

 重生之我要学C++第五天,重生之C++启程,c++,开发语言

 总结:默认构造函数对自定义类型自动调用自定义类型的默认构造方法本质是默认构造函数的默认初始化列表调用自定义类型的默认构造方法。只要构造方法使用默认初始化列表,对自定义类型就会调用它的默认构造方法。反之,手动添加初始化列表就可以选择性的调用自定义类型的构造方法。

3.初始化列表解决的三大问题

(1)类中的引用成员变量

引用在定义的时候必须初始化,否则会出现编译错误,详见重生之我要学C++第二天_无极太族的博客-CSDN博客

重生之我要学C++第五天,重生之C++启程,c++,开发语言

类中的成员都是在初始化列表中定义的,如果成员有引用类型就必须在初始化列表中初始化。

#include<iostream>
using namespace std;
class A
{
public :
	A(int a)
	{
		_a = a;//初始化
	}
private:
	int& _a;
};
int main()
{
	int tmp = 2;
	A a(tmp);
	return 0;
}

此时,引用_a的定义在默认初始化列表中已经完成,在构造函数函数体中在赋值初始化会导致编译错误(定义处未初始化)。

解决方案:在构造函数中手动添加初始化列表,在初始化列表中定义和初始化一并进行。

A(int a)
:
_a(a)
{
	
}
(2)const成员变量

const成员变量容易出问题和引用的原理相同。都是定义处必须初始化。

(3)自定义类型成员没有默认构造函数时的问题

我们知道,构造函数不写初始化列表时,默认初始化列表会调用自定义类型的默认构造函数

默认构造函数:

重生之我要学C++第五天,重生之C++启程,c++,开发语言

 详见:重生之我要学C++第四天_无极太族的博客-CSDN博客

但是如果此时这个自定义类型没有默认构造方法,会出现编译错误

这时候就必须手动添加参数列表,选择性的调用自定义类型具有的构造方法。

运算符重载的应用

第四天我们学习了运算符重载,在这里举两个例子让读者感受到运算符重载的魅力!

(1)顺序表中的运算符重载

先写一个简陋的顺序表

#include<iostream>
using namespace std;
class Sequence
{
public:
	Sequence()
	{
		//初始化
		_a = (int*)malloc(4 * sizeof(int));
		_size = 0;
		_capcity = 4;
	}
	void Push(int x)
	{
		//检查容量:此处忽略
		
		_a[_size] = x;
		_size++;
	}
	void Print()
	{
		for (int i = 0; i < _size; i++)
		{
			cout << _a[i] << " ";
		}
	}
private:
	int* _a;
	int _size;
	int _capcity;
};
int main()
{
	Sequence s;//创建顺序表
	s.Push(1);//尾插三个数据
	s.Push(2);
	s.Push(3);
	//打印顺序表
	s.Print();
	return 0;
}

我们可以在类内部将[ ]重载一下

int& operator[](int i)
{
	return _a[i];
}

此时,顺序表内的元素就可以像数组一样访问:

int main()
{
	Sequence s;//创建顺序表
	s.Push(1);//尾插三个数据
	s.Push(2);
	s.Push(3);

	//打印顺序表
	cout << s[0]<<s[1]<<s[2]<<endl;
	return 0;
}

重载[ ]后,可以让顺序表更加形象,大大增强了代码的可读性。 

(2)自定义类型的流插入流提取

用Date类来举例

#include<iostream>
using namespace std;
class Date//类Date
{
public:
	Date(int year=1, int month=1, int day=1)//构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "年" << _month << "月" << _day << "天" << endl;
	}
private:
	//成员变量的声明
	int _year;//内置类型成员
	int _month;
	int _day;
};
int main()
{
	Date d1(1,1,2);
	d1.Print();
	return 0;
}

可以使用Print函数来打印日期

重生之我要学C++第五天,重生之C++启程,c++,开发语言

 但是如果这样也可以打印日期,是不是会觉得赏心悦目

cout<<d1<<endl;

下面我们就利用运算符重载来实现这个想法。

#include<iostream>
using namespace std;

class Date//类Date
{
public:
	friend ostream& operator<<(ostream& out, Date& d);//将此函数声明为类Date的友元函数
	Date(int year=1, int month=1, int day=1)//构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "年" << _month << "月" << _day << "天" << endl;
	}
private:
	//成员变量的声明
	int _year;//内置类型成员
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "天";
	return out;
}
int main()
{
	Date d1(1, 1, 2);
	cout << d1;
	
	return 0;
}

 运行结果:

重生之我要学C++第五天,重生之C++启程,c++,开发语言

 这里cout是ostream类的对象,将运算符重载写为全局函数就可以调换cout对象和d对象的位置。使用友元函数使得在类外面的函数可以访问类的private成员。下篇文章会介绍友元函数。

今天的分享就到这里啦,如果对大家有用的话,希望程序猿们可以三连支持一下,会继续分享知识!谢谢!文章来源地址https://www.toymoban.com/news/detail-618481.html

到了这里,关于重生之我要学C++第五天的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 重生之我要学C++第七天(匿名对象、内部类)

    这篇文章主要内容是构造函数的隐式类型转化、匿名对象、内部类。希望对大家有所帮助。 更多优质内容跳转: ​​​​​​专栏:重生之C++启程(文章平均质量分93) 目录 构造函数的隐式类型转化 1.单参数构造函数隐式类型转换 2.多参数构造函数隐式类型转换 匿名对象 内部

    2024年02月13日
    浏览(38)
  • 重生之我要学C++第六天(const,static,友元)

    这篇文章的主要内容是const以及权限问题、static、友元函数和友元类,希望对大家有所帮助,点赞收藏评论支持一下吧! 更多优质内容跳转: 专栏:重生之C++启程(文章平均质量分93) 目录   const以及权限问题 1.const修饰内置类型 (1).const修饰普通变量 (2).const修饰指针变量

    2024年02月14日
    浏览(32)
  • 重生c++系列之类与对象(中篇)

    好的继上期,我们今天带来c++类与对象系列的继续学习。 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员 函数。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为

    2024年02月11日
    浏览(40)
  • 重生学c++系列第三课类和对象(上)

        好的我们重生c++系列的前两期已经介绍完了c++祖师爷针对C语言补充的几个新功能,现在我们进入c++的真正课题学习—— 类与对象:      C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。     比如说我们洗菜做饭,C语言关注的是

    2024年02月14日
    浏览(48)
  • C语言(第三十五天)

    3. 移位操作符 左移操作符 右移操作符 注:移位操作符的操作数只能是整数。 3.1 左移操作符 移位规则:左边抛弃、右边补0 3.2 右移操作符 移位规则:首先右移运算分两种: 1. 逻辑右移:左边用0填充,右边丢弃 2. 算术右移:左边用原该值的符号位填充,右边丢弃 警告⚠️

    2024年02月10日
    浏览(41)
  • 七天学会C语言-第五天(函数)

    有参函数是一种接受输入参数(参数值)并执行特定操作的函数。通过向函数传递参数,你可以将数据传递给函数,让函数处理这些数据并返回结果。 例1:编写一程序,要求用户输入4 个数字,输出前两个数中的最大数、后两个数中的最大数以及四个数中的最大数。 运行结

    2024年02月07日
    浏览(40)
  • 拒绝摆烂!C语言练习打卡第五天

    🔥 博客主页: 小王又困了 📚 系列专栏: 每日一练 🌟 人之为学,不日近则日退  ❤️ 感谢大家点赞👍收藏⭐评论✍️   目录 一、选择题 📝1.第一题  📝2.第二题 📝3.第三题 二、编程题 📝1.第一题  📝2.第二题 🗒️前言: 在前面我们学习完C语言的所以知识,当然练

    2024年02月11日
    浏览(36)
  • 第八十五天学习记录:C++核心:内存分区模型

    C++程序在执行时,将内存大方向划分为4个区域 1、代码区:存放函数体的二进制代码,由操作系统进行管理 2、全局区:存放全局变量和静态变量以及常量 3、栈区:由编译器自动分配释放,存放函数的参数值,局部变量等 4、堆区:由程序员分配和释放,若程序员不释放,程

    2024年02月12日
    浏览(46)
  • Spring第五天(注解开发)

    首先,注解配置Bean时xml需要在写在context中,所以我们先来配置xml 可以看到,与之前的Bean配置的区别为这种方法可以直接设置需要扫描的包,自动扫描包内注解了的Bean,那么下面就看如何注解类,以BookDao距离  可以看到,注解的部分为@Component(\\\"bookDao\\\"),所以在获取该Bean时 可

    2024年01月21日
    浏览(36)
  • 十四天学会C++之第五天:类的详细讨论

    什么是友元函数和友元类,它们的作用。 如何声明和使用友元函数和友元类,访问类的私有成员。 友元函数(Friend Functions) 友元函数是一种特殊的函数,它被允许访问类的私有成员。这意味着即使成员是私有的,友元函数也能够直接访问它们,而不需要通过公有接口。这提

    2024年02月07日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包