首页 > 其他分享 >类和对象(中)

类和对象(中)

时间:2024-10-27 10:17:12浏览次数:7  
标签:对象 month int year Date day 构造函数

目录

一.默认成员函数

二.构造函数

三.析构函数

四.拷贝构造函数

五.赋值运算符重载

什么是运算符重载?

赋值运算符重载

六.取地址运算符重载

附件:日期类的实现


一.默认成员函数

在类中,有我们自己实现的成员函数。但是,还有一些“隐而不现”的成员函数,由编译器自己生成,称为默认成员函数。顾名思义,用户无须实现,编译器自动生成。

那么,这些隐而不现的函数是什么,有什么功能呢?

在C++98的标准下,默认生成了6个成员函数:

C++11增加了移动构造和移动赋值两个成员函数(不作讲解)。

我们要明确两点:1.我们不显示实现,这些默认生成的函数行为是什么?

                              2.我们显示实现后,编译器就不会自动生成了,那该如何实现?

二.构造函数

功能:构造函数,完成的是在用类实例化出对象时完成对象的初始化工作

用代码来理解:

typedef int STDataType;
class Stack
{
public:
    //Init
	void Init(int n = 4)
	{
		_a = (STDataType*)malloc(sizeof(STDataType) * n);
		if (_a == nullptr)
		{
			perror("malloc fail");
			return;
		}
		_top = 0;
		_capacity = 0;
	}
    
    //构造函数
	Stack(int n = 4)
	{
		_a = (STDataType*)malloc(sizeof(STDataType)*n);
		if (_a == nullptr)
		{
			perror("malloc fail");
			return;
		}
		_top = 0;
		_capacity = 0;
	}
private:
	STDataType* _a;
	int _top;
	int _capacity;
};

int main( )

{

        //手动调用Init函数初始化

        Stack st1;

        st1.Init();

        

        //自动调用构造函数初始化

        //Stack st2;
        return 0;

}

 构造函数的功能相当于代替了Init函数,它的便捷性在于,在创建对象时自动调用。因此,以后便不在需要实现Init函数,转而实现构造函数。

构造函数的特点:

1.函数名:与类名相同

2.无返回值(注意:不是void)

3.可以构成函数重载

4.对象实例化时,自动调用

认识三个默认构造函数(零实参构造函数):

无参构造,全缺省构造,编译器自动生成的构造

我们在对象实例化的过程中,构造函数的调用是自动的,如果我们不传实参,就能调用的构造函数,称为默认构造函数。 

Date类样例:

class Date
{
public:
	//无参构造
	Date()
	{
		_year = 2024;
		_month = 1;
		_day = 1;
	}

	//带参构造
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	//全缺省构造
	//Date(int year = 2024, int month = 1, int day = 1)
	//{
	//	_year = year;
	//  _month = month;
	//	_day = day;
	//}
	private:
	int _year;
	int _month;
	int _day;
};

int main( )

{

        //假设Date类中,我们实现了一个无参构造和代参构造

        Date d1;

        Date d2(2000,1,1);

 }

 由于d1要自动调用构造函数,因此我们不传实参时,它会去找到它的默认构造函数(无参构造)。

int main( )

{

        //假设Date类中,我们实现了一个全缺省构造

        Date d1;

        Date d2(2000,1,1);

 }

上述d1去调用类中的全缺省构造,由于我们不传实参,d1会使用缺省值。

注意,全缺省构造和无参构造不能同时存在,否则会产生调用歧义。

可以认为,全缺省构造 = 无参构造 + 带参构造

用户不显示实现构造函数,编译器默认生成的构造函数的行为

1.对于内置类型的初始化没有要求。

2.对于自定义类型,调用这个成员变量的默认构造函数。

自定义类型:语言提供的原生数据类型,如char/int/double/指针等。

内置类型:我们使用class/struct定义的类类型。

三.析构函数

功能:与构造函数功能相反,完成对象资源的清理和释放工作。

析构函数的特点:

1.函数名:~类名,如~Date

2.无参,无返回值

3.一个类只能有一个析构函数

4.对象生命周期结束时,自动调用析构函数

5.一个局部域的多个对象,C++规定后定义的先析构

编译器默认生成的析构函数的行为

1.对于内置类型,不作处理。

2.对于自定义类型,自动调用成员变量的析构函数。需要注意的是,自定义类型无论什么情况都会调用它的析构函数。

四.拷贝构造函数

功能:实例化对象时,用已存在的对象拷贝构造新对象。

拷贝构造函数的特点:

1.函数名与类名相同

2.第一个参数必须是当前类类型的引用

3.无返回值

4.C++规定,自定义类型的传值传参和传值返回,都会去调用拷贝构造

 编译器默认生成的拷贝构造函数 的行为:

1.对于内置类型成员变量会完成值拷贝/浅拷贝

2.对于自定义类型的成员变量,会去调用它的拷贝构造

五.赋值运算符重载

什么是运算符重载?

C++语言允许通过运算符重载的形式,给运算符定义新的含义,使得运算符能够适用于自定义类型。

运算符重载本质上是一个函数,函数名有特别的规定:operator运算符,例如:operator+,operator-。函数参数必须包含至少一个自定义类型的参数。

对于二元运算符,运算符左侧的操作数默认作为第一个参数 ,右侧操作数作为第二个参数。如果重载为成员函数,参数个数比运算符操作数少一个;左侧操作数传入隐藏的this指针,右侧操作数传入(第一个)形参位置。

前置++/--与后置++/--的区分:以++为例,重载前置++和后置++时,函数名都是operator++,无法做出很好的区分。于是,C++规定,重载后置++时,参数列表多一个int类型的形式参数

重载<< 和 >> 时,如果重载成成员函数,隐藏的this指针占据了左操作数的位置,会出现 对象<<cout 或 对象 >> cin 的用法,不符合习惯。所以,上述运算符需要重载为全局函数,把ostream/istream放到第一个形参的位置。

五个无法重载的运算符:.*      ::       sizeof       ?:         .

赋值运算符重载

功能:用于两个已存在对象的直接拷贝赋值。

赋值运算符重载的特点:

1.函数名:operator=

2.参数: 建议写成const当前类类型的引用,减少拷贝构造

3.返回类型:建议写成当前类类型的引用,减少拷贝构造

编译器默认生成的赋值运算符重载函数的行为:

1.对于内置类型,完成值拷贝/浅拷贝赋值

2.对于自定义类型,调用自定义类型成员变量的赋值运算符重载

 

六.取地址运算符重载

功能:不让别人取到当前类对象的(真实)地址,返回一个任意地址 

分为const取地址运算符重载和普通取地址运算符重载。

一般无需自己实现,使用编译器默认生成的即可。

扩展:

const 成员函数,cosnt修饰的是隐藏的this指针,因此在const成员函数内,无法修改当前类类型的成员变量。

附件:日期类的实现

功能:实现日期加减天数,日期-日期等功能

Date.h

#pragma once
#include <iostream>
using namespace std;

class Date
{
	//友元声明
	//流插入<<
	friend ostream& operator<<(ostream& out, const Date& d);
	//流提取
	friend istream& operator>>(istream& in, Date& d);

public:
	//类中定义的成员函数,默认inline
	int GetMonthDay(int year, int month)
	{
		static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			return 29;
		}
		return monthDayArray[month];
	}

	bool CheckDay(int year, int month, int day)
	{
		if (month <= 0 || month >= 13 || day > GetMonthDay(year, month) || day <= 0)
			return false;

		return true;
	}

	//构造函数
	Date(int year = 2024, int month = 1, int day = 1);
	
	//逻辑运算符
	bool operator==(const Date& d);
	bool operator!=(const Date& d);
	bool operator>=(const Date& d);
	bool operator<=(const Date& d);
	bool operator>(const Date& d);
	bool operator<(const Date& d);


	//算术运算符
	Date& operator+=(int day);
	Date& operator-=(int day);
	Date operator+(int day);
	Date operator-(int day);

	Date operator++(int);//后置++
	Date& operator++();//前置++
	Date operator--(int);//后置--
	Date& operator--();//前置--

	//d1 - d2
	int operator-(const Date& d);
private:
	int _year;
	int _month;
	int _day;
};
//流插入<<
ostream& operator<<(ostream& out, const Date& d);
//流提取>>
istream& operator>>(istream& in, Date& d);

Date.cpp

#define _CRT_SECURE_NO_WARNINGS
#include "Date.h"

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	
	//日期合法性
	if (!CheckDay(year, month, day))
	{
		cout << "非法日期:" << *this;
	}
}





//逻辑运算符
bool Date::operator==(const Date& d)
{
	if (_year == d._year)
	{
		if (_month == d._month)
		{
			return _day == d._day;
		}
		else
		{
			return false;
		}
	}
	else
	{
		return false;
	}
}

bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}

bool Date::operator>=(const Date& d)
{
	return (*this == d) && (*this > d);
}

bool Date::operator<=(const Date& d)
{
	return !(*this > d);
}

bool Date::operator>(const Date& d)
{
	if (_year > d._year)
	{
		return  true;
	}
	else if (_year == d._year)
	{
		if (_month > d._month)
		{
			return true;
		}
		else if (_month == d._month)
		{
			return _day > d._day;
		}
	}

	return false;
}

bool Date::operator<(const Date& d)
{
	return !(*this >= d);
}




//算术运算符
Date& Date::operator+=(int day)
{
	if (day < 0)
		*this -= (-day);

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}

Date& Date::operator-=(int day)
{
	if (day < 0)
		*this += (-day);

	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

Date Date::operator+(int day)
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}

Date Date::operator-(int day)
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}

Date& Date::operator++()
{
	*this += 1;
	return *this;
}

Date Date::operator--(int)
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}

Date& Date::operator--()
{
	*this -= 1;
	return *this;
}


//日期-日期
int Date::operator-(const Date& d)
{
	int cnt = 0;
	Date greater = *this;
	Date less = d;
	int flag = 1;

	if (greater < less)
	{
		greater = d;
		less = *this;
		flag = -1;
	}

	while (less != greater)
	{
		++less;
		cnt++;
	}

	return cnt * flag;
}




//流插入<<
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}
//流提取>>
istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请输入年月日:";
		in >> d._year >> d._month >> d._day;

		if (!d.CheckDay(d._year, d._month, d._day))
		{
			cout << "日期非法,请重新输入!!!" << endl;
		}
		else
		{
			break;
		}
	}

	return in;
}

 

今天的内容就到这里,感谢大家的支持 !!!

标签:对象,month,int,year,Date,day,构造函数
From: https://blog.csdn.net/2302_81053095/article/details/143228408

相关文章

  • 实验2 类和对象——基础编程1
    一、实验目的 加深对类,对象的理解,能够解释类的封装,类的接口会使用C++语法规则正确定义,实现,测试类,会使用类创建对象,并基于对象编程针对具体问题场景,练习运用面向对象思维进行设计,合理利用C++语言特性(访问权限控制,static,friend,const),在数据共享和保护之间达到平衡会用多文件......
  • Java面向对象
    **Java面向对象学习心得**在学习Java的过程中,面向对象编程(OOP)无疑是最重要的概念之一。Java是一门纯面向对象的编程语言,它通过类和对象的概念使得程序设计更为清晰、模块化,并且便于维护和扩展。以下是我在学习Java面向对象编程过程中的一些心得体会。一、理解面向对象的......
  • 实验2 类和对象_基础编程1
    task1:t.h1#pragmaonce23#include<string>45//类T:声明6classT{7//对象属性、方法8public:9T(intx=0,inty=0);//普通构造函数10T(constT&t);//复制构造函数11T(T&&t);//移动构造函数12~T();......
  • ts:对象数组的简单使用
    ts中对象数组的简单使用一、主要内容说明二、例子1、源码12、源码1运行效果三、结语四、定位日期一、主要内容说明平常ts创建数组的格式如下:letarray:string[]=["元素1","元素2","元素3","元素3","元素4",---]元素1、元素2、元素3,等这些元素,可以为字符,数字,也可以......
  • C++ (4) 面向对象编程,C++的魔法生物养成记
    面向对象编程:C++的魔法生物养成记在C++的世界里,面向对象编程(OOP)就像是魔法生物的养成游戏。你将扮演一名魔法师,通过编写代码来创造和培养自己的魔法生物。这些生物拥有自己的属性(数据)和能力(函数),它们可以在你的程序世界中自由行动和互动。现在,让我们拿起魔杖(键盘),开始这场魔......
  • 面向对象程序设计
    第一次博客作业一、前言第一次作业第一次作业有五道题,前四道为入门及简单的小题,最后一题为难度较大的答题判断程序。主要考察对类的属性和方法的设计与使用,以及在规定格式下对程序用户的输入进行解析从而获取题目、答卷等信息。第二次作业第二次作业有四道题,前三道为难度入门......
  • 实验2 类和对象_基础编程1
    实验任务一源码1#pragmaonce23#include<string>45classT{6public:7T(intx=0,inty=0);8T(constT&t);9T(T&&t);//移动构造函数10~T();11voidadjust(intratio);//按系数成倍调整数据12voiddisplay()con......
  • 实验2 类和对象_基础编程1
    任务1:t.h#pragmaonce#include<string>//类T:声明classT{//对象属性、方法public:T(intx=0,inty=0);//普通构造函数T(constT&t);//复制构造函数T(T&&t);//移动构造函数~T();//析构函数voidadjus......
  • 【Web前端】JavaScript 对象基础
     JavaScript是一种以对象为基础的编程语言,操作数据时,实际都是在处理对象。可以使用简单的数据类型(如字符串、数字和布尔值)来实现一些功能,但深入了解JavaScript对象的运作,将使你能够编写更强大和灵活的代码。对象基础JavaScript中,对象是由一组键(或属性)和值组成的无......
  • 实验2 类和对象_基础编程1
    1.实验任务1t.h源代码:1#pragmaonce2#include<string>34//类T:声明5classT{6public:7//对象属性、方法8T(intx=0,inty=0);//普通构造函数9T(constT&t);//复制构造函数10T(T&&t);......