c++ - 类与对象 - explicit关键字 | static成员 | 友元 | 内部类 | 匿名对象


一、 explicit关键字

1、隐式类型转换
再进行隐式类型转换是会产生一个临时变量tmp,再用临时变量进行赋值。

如:

double d = 1.2;
//再用 d 给 i 进行赋值时,会进行隐式类型转换。
//过程:产生 tmp  = 1 ,再用 tmp 给 i 进行赋值
int i = d;

在这里插入图片描述

那么对于类来说是否也能进行这样的隐式类型转换呢?
答:是的,比如 int 转为 类 , 先用 int i 进行转换为 类类型 A(这个过程会调用构造函数进行构造出一个临时类(tmp)),再用 tmp 拷贝到 A 即完成了隐式类型转换。

如:

class A
{
public:
	//有参构造
	A(int a)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}

	//拷贝构造
	A(const A & a)
	{
		cout << "A(const A & a)" << endl;
	}
private:
	int _a;

};

int main()
{
	A aa = 3;
	//等价与  A tmp(3) , A aa = tmp; 
	//先将 3(int) 隐式转换为 自定义类型 A (tmp),再aa = tmp (拷贝构造)

	return 0;
}

在这里插入图片描述
在这里插入图片描述
上面演示的是单参数的隐式转换,下面是多参数的隐式转换

//多参数隐式类型转换
class A
{
public:
	//有参构造  多参数
	A(int a,int b)
		:_a(a)
		,_b(b)
	{
		cout << "A(int a)" << endl;
	}
private:
	int _a;
	int _b;
};

int main()
{
	//调用格式 ,也可 aa{1,2},但是不建议这种
	A aa = { 1,2 };
	return 0;
}

补充:
临时变量具有常量性。

int main()
{
	double d = 1.12;

	//int i = d; 正常进行隐式转换

	//int& i = d;	//引用临时变量  过程 const int tmp -> int &i = tmp 但是tmp是常量所以会报错 

	//正确做法	//临时变量如果被引用生命周期会延长,不然用完就销毁了
	const int& i = d;
	return 0;
}

在这里插入图片描述

2、如果不想要编译器进行隐式类型转换呢?
使用 explicit 关键字 就可以了
如:

explicit A(int a,int b)
	:_a(a)
	,_b(b)
{
	cout << "A(int a)" << endl;
}

二、static成员

1、概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。

class A
{
public:
	//静态成员函数
	static void Print()
	{
		cout << _a << endl;
	}

private:
	//静态成员变量
	static int _a;
};

//在类外定义
int A::_a = 10;

2、static成员的特征

(1). 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
(2). 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
(3). 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
(4). 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
(5). 静态成员也是类的成员,受public、protected、private 访问限定符的限制

class A
{
public:
	//静态成员函数
	static void Print()
	{
		cout << _a << endl;
		//静态函数不能访问非静态成员
		//cout << _b << endl;
	}

	//静态成员变量  声明
	static int _a;
	int _b = 10;
};

//在类外定义
int A::_a = 10;

int main()
{
	A a1;
	cout << sizeof(a1) << endl; // 大小为 4 ,_a 存在静态区

	A a2;
	cout << "直接通过类来访问" << A::_a << endl;
	cout << "a1:" << a1._a << endl;		// a1._a == a2._a 这个成员变量共享
	cout << "a2:" << a2._a << endl;		//当前在公共区域,当设置为私有时对象就不可访问了

	return 0;
}

在这里插入图片描述

3、静态和非静态的区别

1、调用方式:
非静态成员函数:需要通过类的实例来调用。
静态成员函数: 可以通过类名直接调用,也可以通过实例调用。
2. 访问成员:
非静态成员函数: 可以访问类的实例中的非静态成员变量和其他成员函数。
静态成员函数: 不能直接访问类的实例成员,只能访问类的静态成员变量和其他静态成员函数。
3. this指针:
非静态成员函数: 隐含地有一个指向当前对象的指针(this指针)。
静态成员函数: 没有this指针,因为它与特定的实例无关。

三、友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

关键字:friend

1、友元函数
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

(1)如:重载 << 操作符
我们知道 重载 << 操作符时,不能定义为成员函数,所以只能使用全局函数了,但是类的成员变如果是私有的,对象就无法访问成员变量了,这时使用友元函数就可以很好解决这个问题。

class A
{
	//声明友元函数
	friend ostream& operator<<(ostream& _cout, A& a);
public:


private:
	int _a = 10;
};

ostream& operator<<(ostream& _cout, A &a)
{
	//作为友元函数来访问私有成员
	_cout << a._a << endl;
	return _cout;
}

(2)友元函数的特征

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

2、友元类

(1)友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
(2)友元关系是单向的,不具有交换性。
(3)友元关系不能传递 如果C是B的友元, B是A的友元,则不能说明C时A的友元。
(4)友元关系不能继承。

class B;
//友元类
class A
{
	//B 类作为 A类的友元
	friend class B;
public:
	void Print(B& b)
	{
		//A类不可以访问B类 ,不具有交换性
		//cout << b._b << endl;
	}
	

private:
	int _a = 10;
};

class B
{
	friend class C;
public:
	void Print(A& a)
	{
		//可以访问非公有成员
		cout << a._a << endl;
	}
private:
	int _b = 10;
};

class C
{
public:
	void Print(A& a)
	{
		//友元关系不能传递,这里无法访问到A类的非公有成员
		//cout << a._a << endl;
	}
};

四、内部类

1、概念

如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限,但是内部类就是外部类的友元类。

2、特征

(1). 内部类可以定义在外部类的public、protected、private都是可以的,但是也会受到这些作用符限定。
(2)注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
(3) sizeof(外部类)=外部类,和内部类没有任何关系。

//内部类
class A
{
public:
	//B类 默认作为 A类友元
	class B
	{
	public:
		void P(A& a)
		{
			//可以直接访问a的非公有成员
			cout << a._a << endl;

			//可以直接访问A类的静态成员
			cout << s_a << endl;
		 }

	private:
		int _b = 10;

	};



private:
	int _a = 10;
	static int s_a;
};
int A::s_a = 20;


int main()
{
	A a;

	cout << "A类的大小:" << sizeof(a) << endl; //4,不受到B类的干扰

	//使用B类
	A::B  b;

	//访问b类成员函数
	b.P(a);

	return 0;
}

在这里插入图片描述

五、匿名对象

//匿名对象
class A
{
public:
	A(int a = 10)
		:_a(a) 
	{}
	int get()
	{
		return _a;
	}

private:
	int _a;

};

int main()
{
	//正常实例化对象  生命周期从定义到main函数结束
	A a1;
	A a2(10);

	//匿名对象	生命周期仅仅就是定义这行
	A();
	A(10);

	//一些作用如:想调用非静态成员函数

	//用匿名对象
	A().get();	

	//一般用法  ,比匿名对象繁琐
	A a3;
	a3.get();

	return 0;

}
  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值