【C++】类与对象(下篇)

在本篇博客中,作者将会讲解类与对象的最后一篇。

 一.再谈构造函数

在类与对象(上篇)中,我们讲到了构造函数,其实构造函数就是给每个成员变量进行赋值!!!

仅仅只是赋值而已,并不算严格意义上的初始化

#include<iostream>
using namespace std;

class Date
{
public:
    //实例化对象时,同时给成员变量赋值
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Show()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

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

初始化列表 

 既然普通构造函数并不是初始化,那么什么才是初始化呢?答案是初始化列表

#include<iostream>
using namespace std;

class Date
{
public:
	//初始化列表用法
	Date(int year = 0, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	void Show()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

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

为什么要有初始化列表呢?因为有些成员变量不能通过普通构造函数来赋值:如:引用变量、const常量、自定义类型(且该类没有默认构造函数)。 

#include<iostream>
using namespace std;

class Date
{
public:
	//无默认构造函数(默认构造函数是指:不需要传参的的构造函数)
	Date(int year,int month,int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	void Show()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

class Temp
{
public:
	Temp(int& ptmp)
		:_a(ptmp)
		,_b(10)
		,_d(0,0,0)
	{}
	void Show()
	{
		cout << _a << " " << _b << endl;
	}
private:
	//必须要用初始化列表的三个成员变量
	int& _a;
	const int _b;
	Date _d;//自定义类型,且无默认构造函数
};

int main()
{
	int tmp = 0;
	Temp t1(tmp);
	return 0;
}

最后,初始化列表的初始化顺序与构造函数的初始化列表无关,与成员变量的定义先后有关 

二.static成员

static成员变量

被static修饰的成员变量称为静态成员变量,静态成员变量不属于某个实例化对象,它是所有类对象共享的。且静态成员变量不能在类中初始化,必须在类外初始化

#include<iostream>
using namespace std;

class Date
{
private:
	int _year;
	static int count;
};

int Date::count = 0;

int main()
{
	return 0;
}

static成员函数

被static修饰的成员函数没有this指针。在前面讲到,类的成员函数都会带上一个默认的this指针,而被static修饰的成员函数没有this指针。 

三.友元 

友元函数

什么是友元函数?

我们知道在C++类中,成员变量都会有一个访问修饰符,其中private和protect是私有和保护的,被这两个修饰的成员变量不能被类外部访问,只能被类内部访问,那么如果我们想在外部用函数来对类内部的成员变量进行访问,就可以用友元函数。

#include<iostream>
using namespace std;

class Date
{
	//声明Show是友元函数
	friend void Show(const Date& d);
public:
	Date(int year=0,int month=1,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};

void Show(const Date& d)//可以在类外部访问类内部的成员变量
{
	cout << d._year << "-" << d._month << "-" << d._day << endl;
}

int main()
{
	Date d1(2024, 3, 24);
	Show(d1);
	return 0;
}

看到这里,可能会有人疑惑,我直接在类内部定义一个Show函数就好了吗,为什么还要搞一个友元函数?因为有一些地方必须要用到友元函数。 

友元函数重载<<

在C++中,如果我们想输出某个内置类型变量,直接cout<< 变量名即可,那如果我们想输出自定义类型,则需要额外写一个Show函数,而且每次都要调用该类的函数,那么有没有办法可以使用 cout<<类实例化对象 这样的方式来实现输出了,答案是可以的。


 在类与对象(中篇)中,我们讲到了操作符重载,即我们可以重载<<这个操作符来实现。

常规做法实现
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year=0,int month=1,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	ostream& operator<<(ostream& out)//重载<<操作符
	{
		cout << _year << "-" << _month << "-" << _day << endl;
		return out;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2024, 3, 24);
	Date d2(2024, 3, 25);
	d2 << (d1 << cout);
	return 0;
}

我们可以发现如果在类中定义重载<<操作符,会发现,它的使用方式和常规使用方式不同,它是反过来的,因为在operator<<函数中,会默认有个this指针占了第一个参数的位置,同时d1<<cout 等价于 d1.operator<<(&d1,cout),导致<<使用方法与原本相反,这时,我们就需要使用友元函数来解决。 

友元函数实现 

通过使用友元函数的实现可以达到我们想要的效果。  


 友元类

友元类就是,A类是B类的朋友,所以A类可以突破访问权限限制,可以去访问B类的非公有成员变量。

#include<iostream>
using namespace std;

class Time
{
	friend class Date;//声明Date类是它的朋友
public:
	Time(int hour=0,int min=0,int second=0)
		:_hour(hour)
		,_min(min)
		,_second(second)
	{}
private:
	int _hour;
	int _min;
	int _second;
};

class Date
{
public:
	Date(int year,int month,int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	void SetTime(int hour, int min, int second)//这个函数可以突破访问权限去访问Time的成员变量
	{
		_t._hour = hour;
		_t._min = min;
		_t._second = second;
	}
private:
	int _year;
	int _month;
	int _day;

	Time _t;
};

int main()
{
	Date d1(2024, 3, 24);
	d1.SetTime(0, 0, 0);
	return 0;
}

但是这种关系是单向的,Date可以去访问Time,而Time不能去访问Date。同时友元关系不能传递,也不能继承。 

四.匿名对象

匿名对象就是使用类来实例化一个匿名的对象,这个匿名的对象可以直接调用类种的成员函数,但是它的生命周期只有在定义它的那一行

#include<iostream>
using namespace std;

class Solution
{
public:
	int GetSum(int n)
	{
		return n;
	}
};

int main()
{
	Solution().GetSum(10);//实例化一个匿名类去知道调用它的成员函数
	return 0;
}

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值