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

1. 初始化列表

初始化列表存在于构造函数

class A
{
public:
	A(int a)
		:_a(a)
	{}
private:
	int _a;
};

class Date
{
public:
    // 初始化列表是每个成员 定义和初始化 的地方
	// 不管你写不写,每个成员都要走初始化列表,成员初始化列表的 执行顺序 和声明顺序一致
	//如果不写,内置类型:给随机值,自定义类型:调用它的默认构造函数
	Date(int year, int month, int day, int& i)
		: _year(year)
		, _month(month)
		,_a(1)
		,_refi(i)     //等于int& _refi=i;    
	{
		_day = day;          // 赋值
	}

private:
	int _year;              // 每个成员声明
	int _month = 1;
	int _day = 1;
	// C++11支持给缺省值,这个缺省值给初始化列表
	// 如果初始化列表没有显示给值,就用这个缺省值
	// 如果显示给值了,就不用这个缺省值     
	//例如:写了_month的初始化列表,则int _month = 1;中的1,就不会给初始化列表。1也不会去赋值。
	   

	// 必须定义时初始化
	const int _x = 10;  //const类型不可改变,不可赋值,只能初始化
	int& _refi;         //引用定义时必须初始化
	A _a;               //自定义类型成员(且该类没有默认构造函数时)
};

有些场景还是需要初始化列表和函数体混着用。

Stack(size_t capacity)
		:_array((DataType*)malloc(sizeof(DataType) * capacity))
		,_size(0)
		,_capacity(capacity)
	{
	
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

	    memset(_array, 0, sizeof(DataType) * _capacity);
	  
	}

总结:

  • 能用初始化列表就用初始化初始化列。

2. 单参数构造函数的隐式类型转换

  • 编译器识别到了单参数,就进行单参数构造函数,然后这个单参数就变成一个类。
  • 如果不想发生 单参数构造函数的隐式类型转换 或者 多参数构造函数的隐式类型转换(c++11支持),可以在构造函数的声明和定义前加explicit
  • 一个表达式,连续的步骤里面,连续的构造会被合并,拷贝构造也是构造。
class A
{
public:
	A(int a)     //explicit A(int i) 则取消 隐式类型转换
		:_a(a)
	{}
private:
	int _a;
};

class B
{
public:
	B(int b1, int b2)           //explicit B(int b1, int b2) 则取消 隐式类型转换
	//explicit B(int b1, int b2)
		:_b1(b1)
		,_b2(b2)
	{}
private:
	int _b1;
	int _b2;
};

...

int main()
{
	A aa1(1);

	// 单参数构造函数的隐式类型转换
	// 用2调用A构造函数生成一个临时对象,再用这个对象去拷贝构造aa2
	//例如:const A& ref1 = 2; 中 ref1 就是一个临时对象
	// 编译器会再优化,优化用2直接构造 
	A aa2 = 2;

	SeqList s;       //该顺序表中存储类对象
	s.PushBack(3);
	//等价于
	/*A aa3(3);        
	s.PushBack(aa3);*/
  
    // C++11 支持多参数的隐式类型转换
    B bb1(1, 1);
	B bb2 = { 2, 2 };
	const B& ref2 = { 3,3 };
   
   return 0;
}

3. 匿名对象

  • 匿名对象特点:生命周期只在这一行,A(7); 或 A();
  • 有名对象 特点:生命周期在当前局部域,A aa1(6);
  • 匿名对象具有常性
...
int main()
{
	s.PushBack(A(8));
    /*A aa1(8);
	s.PushBack(aa1);*/

    Solution().Sum_Solution(100);
	/*Solution sl;
	sl.Sum_Solution(10);*/

	return 0;
}
  • const引用会延长匿名对象声明周期,本质是将匿名变有名
// ref出了作用域,匿名对象就销毁了
	const A& ref = A();
	A aa2;

4. 类内的static成员

4.1 static成员

  • static成员不储存在类对象内。而是存在静态区,所以静态成员变量属于所有对象,属于整个类。
  • 由于上述原因,private的static成员的声明不能给缺省值。初始化类表里也不会有static成员。静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明。定义eg: int A::n=0;
    在这里插入图片描述

4.2 static成员函数

  • 静态成员函数没有隐藏的this指针,不用类对象就可调用
  • static成员函数不可访问非 static成员。非static成员函数 可访问 static成员。
  • 也可像static成员一样使用A::,而不通过对象调用

牛客题目:关于static的题目

5. 友元

5.1 友元函数

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

5.2 友元类

  • 友元类可访问类的私有和保护成员
  • 友元关系是单向的,不具有交换性。
  • 友元关系不能传递
    如果B是A的友元,C是B的友元,则不能说明C时A的友元。

友员类的例子如下:

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;
 }

6. 内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。

  • B类只受A类域和访问限定符的限制,但其实他们是两个独立的类
  • 内部类就是外部类的友元类,可访问外部类的私有和保护成员。
  • 外部类不可访问内部类的私有和保护成员。
  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值