0
点赞
收藏
分享

微信扫一扫

【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它

生态人 2022-05-03 阅读 42

 

 

目录

值得收藏

类的6个默认成员函数

一、构造函数

1.概念

2.构造函数的特性

3. 显示定义与未显示定义构造函数

二、析构函数 

1.概念

2.析构函数的特性 

三、拷贝构造函数 

1.概念 

2.拷贝构造函数的特性 

3.拷贝构造的注意点

四、赋值运算符重载 

1.运算符重载 

1.概念

2.如何定义及使用

2.赋值运算符重载 

 1.概念

五、日期类实现

1. 日期类的定义

2.日期类的接口实现 

①日期类的构造函数

②日期类比较运算符重载 

③日期类+、-、+=、-=运算符重载

④日期类++、-- 重载

⑤日期 - 日期及获取某天是周几 

⑥对流插入和流提取的重载 

六、const修饰类的成员函数 

七、取地址及const取地址操作符重载


值得收藏 

 

 

类的6个默认成员函数

一、构造函数

1.概念

//定义了一个类--Date
class Date
{ 
//公有
public:
     void SetDate(int year, int month, int day)
     {
         _year = year;
         _month = month;
         _day = day;
     }
 
     void Display()
     {
         cout <<_year<< "-" <<_month << "-"<< _day <<endl;
     }
//私有
private:
     int _year;
     int _month;
     int _day;
};
int main()
{
     Date d1;//实例化出一个对象,d1
     d1.SetDate(2018,5,1);//手动初始化第一次
     d1.Display();
 
     Date d2;//实例化出一个对象,d2
     d2.SetDate(2018,7,1);//手动初始化第二次
     d2.Display();
     return 0; 
}

2.构造函数的特性

定义如下: 

/*构造函数*/
class Date
{
public:
    //以下是自己创建的两个构造函数,分别为无参的和带参的
	Date()//函数名和类名相同,无返回值---无参调用
	{
		_year = 0;
		_month = 1;
		_day = 5;
	}
	Date(int year, int month, int day)//函数名和类名相同,无返回值---带参调用
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;//自动调用无参的构造函数

	Date d2(2022, 1, 5);//自动调用带参的构造函数

    // 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
    // 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
    Date d3();
	return 0;
}
    Date()
	{
		_year = 0;
		_month = 1;
		_day = 5;
	}
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

    //利用缺省将上面的代码转换为下面的代码
    
	Date(int year = 0, int month = 1, int day = 5)
	{
		_year = year;
		_month = month;
		_day = day;
	}

3. 显示定义与未显示定义构造函数

/*如果没有显示定义构造函数,会发生什么情况呢*/
class Date
{
public:
    /*
        未显示定义构造函数

    */

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	return 0;
}

 

class A
{
public:
	A()
	{
		cout << " A()" << endl;
		_a = 0;
	}

	/*A(int a )
	{
		cout << " A()" << endl;
		_a = a;
	}*/
private:
	int _a;
};

class Date
{
public:
	/*
	   未显示定义构造函数

	*/
private:
    //内置类型
	int _year;
	int _month;
	int _day;
    
    //自定义类型
	A _aa;
};

int main()
{
	Date d1;
	return 0;
}

 

 

二、析构函数 

1.概念

2.析构函数的特性 

 定义如下:

class Data
{
public:
    //构造函数
	Data(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
    //析构函数
	~Data()
	{
		cout << '1' << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Data d1;
	Data d2(2022, 1, 15);

	return 0;
}

 

class Data
{
public:
	Data(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	~Data()
	{
		cout << "~Data()" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int));
		if (_a == nullptr)
		{
			cout << "malloc fail\n" << endl;
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}
	//如果我们不写析构函数和构造类函数类似
	//对于内置类型成员变量不作处理
	//对于自定义类型成员变量会去调用它的析构函数
	~Stack()
	{
		free(_a);
		_a = nullptr;
		_top = _capacity = 0;
	}
private:
	int* _a;
	size_t _top;
	size_t _capacity;
};

class MyQueue 
{
public:
private:
	Stack pushST;
	Stack popST;
};

int main()
{
	Data d1;
	Data d2(2022, 1, 15);

	Stack s1;
	Stack s2(20);
	/*先析构s2->s1->d2->d1*/

	MyQueue mq;

	return 0;
}

三、拷贝构造函数 

1.概念 

2.拷贝构造函数的特性 

定义如下: 

class Date
{
public:
	/*构造函数*/
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	/*拷贝构造函数*/
	Date(const Data& d)
	{
		//加const为了防止写成 d._year = _year;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};


int main()
{
	Date d1(2022, 1, 15);

	//拷贝复制
	Date d2(d1);//调用拷贝构造---自定义类型用一个同类型的对象初始化我,就是拷贝构造
	
	return 0;
}

 

3.拷贝构造的注意点

class Stack
{
public:
    //构造函数
	Stack(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int));
		if (_a == nullptr)
		{
			cout << "malloc fail\n" << endl;
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}

    //拷贝构造函数
    /*

        编译器默认生成

    */

    //析构函数
	~Stack()
	{
		free(_a);
		_a = nullptr;
		_top = _capacity = 0;
	}
private:
	int* _a;
	size_t _top;
	size_t _capacity;
};


int main()
{

	/*直接崩溃*/
	//导致他们指向的空间被析构两次,导致程序崩溃
	Stack st1(10);
	Stack st2(st1);

	return 0;
}

 

四、赋值运算符重载 

1.运算符重载 

1.概念

class Data
{
public:
	Data(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

//private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Data d1(2022, 1, 16);
	Data d2(2022, 1, 31);

	int ret = d1._day > d2._day;
	cout << ret << endl;
    //d1 > d2;报错

	return 0;
}

2.如何定义及使用

/*运算符重载*/
class Data
{
public:
	Data(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

//private:
	int _year;
	int _month;
	int _day;
};

/*****类外定义******/

//函数名 operator操作符
//返回类型:看操作符运算后返回值是什么
//参数:操作符有几个操作数,他就有几个参数
bool operator>(const Data& d1, const Data& d2)
{
	if (d1._year > d2._year)
	{
		return true;
	}
	else if (d1._year == d2._year && d1._month > d2._month)
	{
		return true;
	}
	else if (d1._year == d2._year && d1._month == d2._month && d1._day > d2._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}


int main()
{
	Data d1(2022, 1, 16);
	Data d2(2022, 1, 31);


	//默认情况下,C++是不支持自定义类型对象使用运算符
	d1 > d2;//编译器看到这个就会将其转换为operator>(d1,d2),就像函数调用一样
	cout << (d1 > d2) << endl;
	cout << operator>(d1, d2) << endl;
	return 0;
}
class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//bool operator>(const Date& d1, const Date& d2)
	//按照这样去写,是错误的,操作数过多,因为隐含了一个this指针
	//d1.operator > (d2); bool operator>(const Date* this, const Date& d2)  
	//d1就传给了this,d2就传给了d2
	bool operator>(const Date& d2)
	{
		if (_year > d2._year)
		{
			return true;
		}
		else if (_year == d2._year && _month > d2._month)
		{
			return true;
		}
		else if (_year == d2._year && _month == d2._month && _day > d2._day)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
private:
	int _year;
	int _month;
	int _day;
};


int main()
{
	Date d1(2022, 1, 16);
	Date d2(2022, 1, 31);
	d1 > d2;//先去类看有没有这个运算符,没有去全局找  运算符重载一般重载为成员函数,为了解决访问私有变量的问题
	//d1.operator > (d2);类里面转换为这样
	
	return 0;
}

2.赋值运算符重载 

 1.概念

class Date
{
public:
    //构造函数
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
    //拷贝构造
	Date(const Date& d)
	{
		cout << " 11111 " << endl;
	}

    //赋值运算符重载
	//d1 = d3;
	Date operator=(const Date& d)
	{
		//防止有人d1=d1
		//极端情况下自己给自己赋值,判断一下地址就直接跳过了
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

private:
	int _year;
	int _month;
	int _day;
};


int main()
{
	Date d1(2022, 1, 16);
	Date d2(2022, 1, 31);
	Date d3(2022, 2, 26);

	//一个已经存在的对象拷贝初始化一个马上创建实例化的对象
	Date d4(d1);//拷贝构造
	Date d5 = d1;

	//两个已经存在的对象,之间进行赋值拷贝
	d2 = d1 = d3;
	//d1.operator=(d3);
	//d2.operator=(d1.operator=(d3));

	return 0;
}

五、日期类实现

1. 日期类的定义

class Date
{

public:
    //构造函数
	Date(int year = 1, int month = 1, int day = 1);

	//打印
	void Print() const;

	// 获取某年某月的天数
	int GetMonthDay(int year, int month);

	// >运算符重载
	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++();

	// 后置++; 后置为了跟前置++,进行区分,增加了一个参数占位,跟前置++,构成重载
	Date operator++(int);
	// 前置--
	Date& operator--();

	// 后置--
	Date operator--(int);

	// 日期-日期 返回天数
	int operator-(const Date& d);

	//获取某天是周几
	void PrintWeekDay();

private:
	int _year;
	int _month;
	int _day;
};

2.日期类的接口实现 

①日期类的构造函数

// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)const
{
	static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int day = monthDayArray[month];//获取每个月的天数
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		day += 1;//如果是二月并且是闰年,天数就加+1
	}
	return day;
}

//构造函数
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	if (!(_year >= 0
		&& (month > 0 && month < 13)
		&& (day > 0 && day <= GetMonthDay(year, month))))
	{
        //不满足年月日的条件,就是非法的
		cout << "非法日期->";
		Print();
	}
}

//打印
void Date::Print()const
{
	cout << _year << "-" << _month << "-" << _day << endl;
}

②日期类比较运算符重载 

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

// ==运算符重载
bool Date::operator==(const Date& d)const
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
		
}

// <运算符重载
bool Date::operator<(const Date& d)const
{
	return !(*this >= d);
}

// >=运算符重载
bool Date::operator>=(const Date& d)const
{
	return *this > d || *this == d;
}

// <=运算符重载
bool Date::operator<=(const Date& d)const
{
	return !(*this > d);
}

// !=运算符重载
bool Date::operator!=(const Date& d)const
{
	return !(*this == d);
}

③日期类+、-、+=、-=运算符重载

// 日期 += 天数
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;//如果传过来的天数是负数,实际上就是调用-=,把天数变为正数
	}
	_day += day;//先将天数加上
	while (_day > GetMonthDay(_year, _month))
	{
        //凑满本月天数,月进位1
		_day -= GetMonthDay(_year, _month);
		++_month;
        //如果月进位到13时,年进位,月置1
		if (_month == 13)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}

// 日期 + 天数
Date Date::operator+(int day)const
{
	Date ret(*this);
	//ret.operator+=(day);
	ret += day;
	return ret;
}

// 日期 -= 天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;//如果传过来的天数是负数,实际上就是调用+=,把天数变为正数
	}

	_day -= day;//先将天数减去
	while (_day <= 0)
	{
        //向月借位
		--_month;
        //当月借完后,就要向年借位,并把月置1
		if (_month == 0)
		{
			--_year;
			_month = 12;
		}
        //加上当月的天数,直到天数符合条件
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

// 日期 - 天数
Date Date::operator-(int day)const
{
	Date ret(*this);
	ret -= day;
	return ret;
}

④日期类++、-- 重载

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

// 后置++
Date Date::operator++(int)
{
	Date ret(*this);
	//Date ret = *this;
	*this += 1;
	return ret;
} 

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

// 后置--
Date Date::operator--(int)
{
	Date ret(*this);
	//Date ret = *this;
	*this -= 1;
	return ret;
}

⑤日期 - 日期及获取某天是周几 

// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
    //定义出大日期与小日期(假设)
	Date max = *this;
	Date min = d;
	int flag = 1;
    //先进行大小日期的判断,不符合则交换
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;// 这里flag的作用:如果是小日期-大日期,应该是负数
	}
	int count = 0;
	while (min != max)
	{
        //让小日期不断的累加,count记录天数
		++min;
		++count;
	}
	return count * flag;
}

//获取某天是周几
void Date::PrintWeekDay()const
{
	const char* arr[] = { "周一","周二", "周三", "周四", "周五", "周六", "周日" };
	/*Date start(1900, 1, 1);
	int count = *this - start;*/
	int count = *this - Date(1900, 1, 1);//匿名对象
	cout << arr[count % 7] << endl;
}

⑥对流插入和流提取的重载 

//Date.h
class Date
{
	//友元函数
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);

public:
	//构造函数
	Date(int year = 1, int month = 1, int day = 1);
	/*
     ......
     ......
    */

	//void operator<<(ostream& out);//这里就不能实现成 成员函数
	
private:
	int _year;
	int _month;
	int _day;
};
//实现为全局的
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);


//Date.c
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

六、const修饰类的成员函数 

class Date
{
public:
	void Display()
	{
		cout << "Display ()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
	void Display() const
	{
		cout << "Display () const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
void Test()
{
	Date d1;
	d1.Display();

	const Date d2;
	d2.Display();
}

 

七、取地址及const取地址操作符重载

class Date
{ 
public :
     Date* operator&()
     {
         return this;
        //return nullptr;不允许获取对象的地址
     }
 
     const Date* operator&()const
     {
         return this;
     }
private :
     int _year ; // 年
     int _month ; // 月
     int _day ; // 日
};

举报

相关推荐

0 条评论