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

一、构造函数补充

1.构造函数体的赋值

我们来看下面代码:

class Goat
{
	public:
	int a1;   //定义
	int a2;
	const int x;
};
int main()
{
	Goat aa;// 这里是对对象整体的定义,但是每个成员什么时候初始化呢?
	
	return 0;
}

这里就会报错
因为const修饰的变量只能在定义的时候初始化
必须要给每个成员变量找个单独定义的位置,不然遇到const这样的成员不好处理。

所以C++创始人给这样的情况创建了初始化列表

1.2 初始化列表

class B
{
	public:
	B(int b)//需要传参不是默认构造函数
	:b(0)
	{
		cout << "B()" <<endl;
	}
	private:
	int b;
	
}
class Goat
{
	初始化列表在默认构造函数下:由“:”开头,“,”分割
	1.那个对象调用构造函数,初始化列表就是它所有成员变量定义的位置
	2.不管是否显示写在初始化列表,每个变量都会在初始化列表定义
	
	A()
		:x(1)a1(1){
		a1++;
		a2--; 
	 }

	public:
	int a1;   
	int a2;
	const int x;
};
int main()
{
	Goat aa;// 这里是对对象整体的定义,但是每个成员什么时候初始化呢?
	B bb;
	return 0;
}

C++规定有三种情况必须在初始化列表初识化

  1. const int x。(const修饰的变量)
  2. int& ref (引用时必须在初识化列表初始化)
  3. 对于自定义类型成员。(没有默认构造的自定义类型成员)

注意: 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

1.3隐式类型转化

class A
{
public:
	A(int)
	:a1(1)
	{}
private:
	int a2;
	int a1;
};
int main()
{
	A aa1(1);  //调用构造函数
	A aa2 = 1; //类型转换 (隐式类型转换)

	int i = 1;
	double d = i;//隐式类型转化

}

为什么[ A aa2 = 1 ] 时隐式转化呢?
我们来先看下面double类型的转换
在这里插入图片描述
所以自定义类型A也是同理
在这里插入图片描述
所以这里[ A aa2 = 1]应该经历一个构造函数和一个拷贝构造的过程。
不过在最近新的编译器中,这种连着一起执行的构造+拷贝构造,编译器会识别并且直接优化成一个构造。(一定要是构造+拷贝连着一起的执行才会优化,如果分开执行那就不会优化)

1.4explicit关键字

构造函数不仅可以构造与初始化对象,对于接收单个参数的构造函数,还具有类型转换的作用(隐式类型转换)。接收单个参
数的构造函数具体表现:

class A
{
public:
	// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
	// explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译
	explicit A(int a)
	:_a1(a)
	{
		cout << " A(int a)" << endl; 
	}
	//2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具有类型转换作用
	explicit A(int a1,int a2)
	:_a1(a1)
	,a2(a2)
	{}
private:
int _a2;
int _a1;	
}
int main()
{   //单参数构造函数  C++98就支持了
	A aa1(1);  //调用构造函数
	A aa2 = 1; //类型转换 (隐式类型转换)

	//多参数隐式类型转换	C++11之后支持
	A aa3(1,1);
	A aa4 = {22}//也是先构造再拷贝构造不过被编译器优化成了构造
					//注意这里赋值的话要用花括号。
	
}

二、 static成员

2.1 概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化
面试题:实现一个类,计算程序中创建出了多少个类对象。
静态成员变量必须赋初始值

class A 
{
public:
	A()
	{++_count;}
	A(const A& t)
	{++_count;}
	int GetCount()
	{
	return _count;
	}
	

private:
    不属于某个对象,属于所有对象,属于整个类
	static int  _count;
}:
int main()
{
	A aa1;
	A aa2(aa1);
	1.用这种方式i想要获得count的值,执行后我们会发现找不到,因为count是私有变量
	cout << A::count << endl;
	2.解决方法在classpublic写上GetCount()函数,因为GetCount是类里面的函数对象,所以能直接访问到私有变量。
	cout << aa1.GetCount() <<endl;
}

但是以上方法会有局限性,如果main函数这样写呢

void func()
{
	A aa1;
	A aa2(aa1);
	
}
int main()
{   func()
	//这样就会访问不到
	cout << aa1.GetCount() <<endl;
	//只能为了获取到count的值再创建一个对象
	A aa;
	cout << aa.GetCount()-1 <<endl;
	
}

2.2静态成员函数

1.要想有很好的方式解决以上问题,我们需要用到静态成员函数。

	//静态成员函数--没有this指针
	static int GetCount()
	{
		return _count;
	}
	//调用方法:直接类类型调用
	cout << A::GetCount() <<endl;

静态成员函数一般匹配这静态成员变量使用。

2.补充数组构造函数
在这里插入图片描述
这里我们的count值是多少呢?
在这里插入图片描述
答案是12,因为数值里每个值都是A对象类型,所以要调用10次构造函数。

三、友元类

前面已经看过了友元函数今天来看一下友元类
友元类要注意的是:
1.友元关系是单向的,不具有交换性。
2.友元关系不能传递
如果B是A的友元,C是B的友元,则不能说明C时A的友元。

3.友元不能继承

class Time
{
 friend class 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 = 1900, int month = 1, int day = 1)
 	: _year(year)
 	, _month(month)
 	, _day(day)
 	{}
 
 void SetTimeOfDate(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. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系。
class A

{
private:
 static int k;
 int h;
public:
  //内部类 -- 跟A是独立的,只是受A类域的限制,B类的空间是独立的,不会占A类的空间大小。
 class B // B天生就是A的友元
 {
 public:
 	void foo(const A& a)
 	{
 		cout << k << endl;//OK
 	 	cout << a.h << endl;//OK
 	}
 };
};
int A::k = 1;
int main()
{
	 A::B b;    //B类的用法和定义
	 b.foo(A());
 
	 return 0;
}
  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值