类和对象下

一,初始化列表

1,之前我们在实现构造函数的时候,初始化成员变量主要是在函数体内进行赋值,构造函数初始化还有另外一种方式,就是使用初始化列表初始化列表的使用方式是:以一个冒号开始,接着以逗号分割的数据成员列表,每个成员变量后面跟一个放在括号里的初始值或表达式。

2,每个成员变量在初始化列表只能出现一次,语法上可以理解初始化列表是成员变量初始化定义的地方。内置类型可以不初始化,编译器就会给随机值。

class Date
{
public:
	Date(int year=1,int month=1,int day=1)//初始化列表初始化
		:_year(year)
		,_month(month)
		,_day(day)
	{}
private:
	//变量声明
	int _year;
	int _month;
	int _day;
};

成员变量在初始化列表初始化后,还可以在函数体内用。

3,引用成员变量,const成员变量,没有默认构造函数的类类型成员变量,这三类是必须在初始化列表进行初始化的,不能在函数体内初始化。

(1)下面代码是这三类没有在初始化列表初始化。

class Time
{
public:
	//默认构造函数有3类
	//1,全缺省的
	//2,无参的
	//3,编译器默认生成的
	Time(int a )//不是默认构造
		:_a(a)
	{}
private:
	int _a;
};
class Date
{
public:
	Date(int year=1,int month=1,int day=1)//初始化列表初始化
		:_year(year)
		,_month(month)
		,_day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
	int& r;
	const int i;
	Time _t;
};

上面的这段代码就会报错

 (2)原因

对于const修饰的变量,和引用成员变量。

对于没有默认构造的类类型成员变量 ,需要在初始化列表初始化。而有默认构造的,可以不用在初始化列表写,编译器会自动调用的默认构造进行初始化。

4,c++11后,还可以在成员变量声明的地方给缺省值

class Date
{
public:
	Date(int year,int month,int day)//初始化列表初始化
		:_year(year)
		,_month(month)
		//_day没初始化,会用缺省值初始化
	{}
	void print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	//声明,缺省值->在初始化列表没有初始化的,会用缺省值初始化
	int _year=1;
	int _month=1;
	int _day=1;
};

int main()
{
	Date d1(2024, 7, 15);
	d1.print();

	return 0;
}

 5,成员变量在类中的声明顺序就是在初始列表中的初始化顺序。与其在初始化列表中的顺序无关。

6,总的来说,成员变量初始化尽量使用初始化列表。因为不管你是否使用初始化列表,对于自定义类型而言,一定会先使用初始化列表初始化。

二,内置类型转换 

1,c++支持内置类型隐士转化成类类型对象,需要有相关内置类型为参数的构造函数

2,构造函数前加上explicit就不再支持隐士类型转换了。

class A
{
public:
	//explicit A(int a=0) 加上explicit就不支持类型转换了
	 A(int a=0)
		:_a(a)
	{}
	void print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A a1(1);//调用构造函数
	a1.print();

	//类型转换
	A a2 = 2;//先用2调用构造函数,再通过拷贝构造给a2
	        //但是编译器遇到连续构造+拷贝构造,会优化为直接构造
	a2.print();
	
	A& ra1 = a2;//引用
	const A& ra2 = 2;//具有常性,直接引用会扩大权限,编译报错

	return 0;
}

 三,静态成员变量

1,用static修饰的成员,称为静态成员变量,静态成员变量一定要再类外进行初始化。

2,静态成员变量为所有类对象共享,不属于某个单独的类,存放于静态区

3,用static修饰的成员函数成为静态成员函数,静态成员函数没有this指针

4,静态成员函数可以访问静态成员变量,但不能访问非静态的,因为没有this指针。

5,非静态的成员函数,可以访问任意的静态成员变量和静态成员函数。

6,静态成员函数也受访问限定符private,public,protected的限制。

class A
{
public:
	A()
	{
		_scount++;
	}
	A(const A& a)
	{
		_scount++;
	}
	~A()
	{
		_scount--;
	}
	static int GetScount()//静态成员函数,可以访问静态成员,没有this指针
	{
		return _scount;
	}
private:
	static int _scount;//静态成员变量
};
int A::_scount = 0;//类外初始化,需要指明类域

这样就可以计算一个程序中,对象被创建了多少个

int main()
{
	A a1;//构造
	A a2(a1);//拷贝构造
	cout << A::GetScount() << endl;
	//代码块的局部域
	{
		A a3;
		cout << A::GetScount() << endl;
	}
	//出作用域后对象销毁,调用析构函数
	cout << A::GetScount() << endl;

	return 0;
}

四,友元类

1,友元分为友元函数和友元类,再函数声明或者类声明前加上friend,再放到类中。

2,外部友元函数可以访问类的私有和保护成员,友元函数仅仅是一种声明,不是成员函数。

3,友元函数可以放到类的任何地方,不受访问限定符的限制。

4,一个函数可以是多个类的友元函数。

5,友元类中的成员函数都可以看作是另一个类的友元函数,可以访问类中的私有和保护成员。

6,友元类的关系是单向的,并且不具有传递性。

总结:需要访问私有的时候,可以设置为友元。

友元函数

class Date
{
	//声明为友元函数
	friend ostream& operator<<(ostream& out, Date d);
public:
	Date(int year, int month, int day)
		: _year(year),
		_month(month),
		_day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, Date d)
{
	//可以访问私有成员
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

友元类

class Time
{
	friend class Date;
	//声明Date类为友元类,则Date可以直接访问Time的私有成员变量
public:
	Time(int hour = 0, int minute = 0,int second=0)
		:_hour(hour)
		,_minute(minute)
		,_second(second)
	{}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
	
public:
	Date(int year, int month, int day)
		: _year(year),
		_month(month),
		_day(day)
	{}
	void SetTime(int hour, int minute, int second)
	{
		//可以访问私有成员变量
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};

五,内部类

1,如果一个类定义在另一个类内部时,这个类就叫做内部类

2,内部类是一个独立的类,它不属于外部类,不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。

注意:内部类时外部类的友元

特性:

1. 内部类可以定义在外部类的public、protected、private都是可以的。

2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

3. sizeof(外部类)=外部类,和内部类没有任何关系。

六,匿名对象

class Date
{
public:
       Date(int year=1, int month=1, int day=1)
		: _year(year),
		_month(month),
		_day(day)
	    {}
	
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;

	//Date d1();
	//不能这么定义对象,因为编译器不知道是在定义函数,还是对象

	Date();
	//定义匿名对象,不用取名字
	//声明周期只在这一行,到下一行它就会调用析构函数

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值