C++ 有元 内部类 匿名对象

有元

  使用有元就可以突破封装,可以直接对类当中 私有的 成员 成员函数等等进行访问,在某一次上提供了遍历,但是这增大的 耦合性,破坏了封装,所以建议有元不要多用。

所谓耦合性就是 ,某两个 东西的 关系,越紧密,耦合性就越大。其实,我们要实现封装的话,关系紧密不是好的结果。

有元函数

 在类当中使用  friend 关键字修饰一个 在类外 的 普通函数(这个函数不属于任何类),也就是用 friend 关键字 在类当中进行声明,在类外面进行定义,那么这个函数就是这个类的友元函数这个函数就可以访问这个类当中的私有的成员。

 如下面这个例子,因为 成员函数的第一个参数是 对应对象的  this 指针,那么如果我们在 类当中定义重载运算符,第一个参数就必须是 这个对象的this指针,那我们在调用这个函数的时候,左边的变量只能是对象,比如我们重载  "<<" ,那么我们就只能 d1 << cout ,这样写, 如果 cout << d1 ,这样写就会报错。

但是第一种方式不是我们平常的书写习惯,所以我们想到在类外定义,然后为了 这个 "<<" 重载函数能访问到类当中的成员,我们就可以把这个重载运算符的函数,声明为有元函数,即代表着,这个函数是这个类的朋友,那么这个函数就可以访问其中 私有的成员。

 定义在类中:

class Date
{
public:
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
	// 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
	ostream & operator<<(ostream& _cout)
	{
		_cout << _year << "-" << _month << "-" << _day << endl;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};

 定义在 类外:

class Date
{
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;
	return _cout;
}

【注意】:

  •  有元函数可以访问 私有的 受保护的成员,但是不能访问成员函数。
  • 有元函数不能用const 修饰, 因为它不能在类当中定义,没有 this 指针。
  • 有元函数可以在类当中的任何地方进行声明,不受类访问限定符的限制
  • 一个函数可以和多个类进行有元
  • 有元函数的调用和普通函数的调用是相同的

 有元类

 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

 【注意】:

  •  有元是单向的,比如 D1类是 D2类的有元类,那么D1类就可以访问其中的成员函数等等,但是 D2就不能访问 D1 当中的成员函数。
  • 有元不能传递,比如 C 是 B 的有元,B 是 A的有元,但是 C 不是 A的有元。
  • 有元关系不能继承。
class A
{
	friend class B;
public:
	int Get_a()
	{
		return _a;
	}
protected:
	int _a = 1;
};

class B
{
public:
	int GetA_a()
	{
		// 直接访问 A类当中的私有成员
		return a._a;
	}
protected:
	int _b = 0;
	A a;

};

内部类

 定义在类当中的类的就是这个类的内部类,这个内部类,就是一个类,通过外部的 类是没办法访问内部类中的私有的成员的,也就是说内部类不属于外部类。

 我们先来计算一下一个 下列代码当中 A类的 大小:

 我们发现是4,这个4只计算了 _a 这个成员的大小,因为 A 当中的 _b  是静态的,我们说类当中只是的成员只是声明,而定义是在 对象当中,但是静态的成员不存储在对象当中,而是在 全局当中进行 定义。那么 类A 当中的 类B 也是如此,A 中没有 B对象,所以不计算 B 的大小。如果我们在 A的成员中 定义了 B 这个对象那么大小就是 8 了:

 像上述的 B 类 定义的在 A类的 外面,和 B类 定义在 A类当中的 区别就是,前者是在全局域当中定义,后者是在 A这个类域当中定义。

形象的说,如果 类是图纸,对象是对应建造的房子,那么像上述 B是A的内部类,我们创建A类的对象当中是没有B类的空间的,也此时就是在 A的房子中放了 B的 图纸。

那么既然是在 A的类域当中定义,那么这个 B类就可以访问A类当中的私有成员,也就是内部类就是外部类的友元类。但是外部类不是内部类的友元。

class A
{
public:

	class B
	{
	public:
		int GetA_a()
		{
			return a._a;
		}

	protected:
		int _b = 0;
		A a;
	};

protected:
	int _a = 1;
	static int _b;
	B b;
};
  • 1. 内部类可以定义在外部类的public、protected、private都是可以的。
  • 2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  • 3. sizeof(外部类)=外部类,和内部类没有任何关系
     

 只有是 定义出来的才受到 访问限定符的限制,向上述只是声明,所以是不会限制的。

 匿名对象

class A
{
public:
	int Get_a()
	{
		return _a;
	}
protected:
	int _a;
};

int main()
{
	// 匿名创建对象
	A();
}

如上述就是使用 匿名对象的创建一个对象。

使用匿名对象来调用成员函数:

int main()
{
	// 匿名创建对象
	A().Get_a();
}

我们可以使用这样的方式来 一次性调用 类当中的成员函数,如果是多次,那么我们就得使用 普通的创建对象的方式来 调用成员函数了。

之所以这样说,是因为匿名对象是 即用即销毁

有名对象的生命周期是在 函数局部域,匿名函数的生命周期是在当前行

 【注意】:

我们不能这样去调用成员函数:

A::Get_a();

这样调用的前提是 这个函数是静态的,如果这样调用这个函数就必须没有 this 指针。而成员函数是必须有 this 指针的。

匿名对象和 临时对象一样,具有常性,所以,我们不能创建 匿名对象的普通引用:

 所以要加一个 const 才能编译通过:

	const A& pa = A();

而且当我们使用 const 引用这个 匿名对象之后,这个匿名对象的 生命周期会被延长,延长的时间是 引用的生命周期。

 如下面这个例子:

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}

	int Get_a()
	{
		return _a;
	}
protected:
	int _a;
};

class AAAAAAAAA
{
public:
	AAAAAAAAA()
	{
		cout << "AAAAAAAAA()" << endl;
	}

	~AAAAAAAAA()
	{
		cout << "~AAAAAAAAA()" << endl;
	}
};

int main()
{

	const A& pa = A();

	AAAAAAAAA aaaaaaaa;
}

我们把 两个类的 构造函数 和 析构函数 只要已调用就打印一下,表明调用了这个函数,我们来看输出结果:

 我们发现, A() 这个匿名函数是在 AAAAAAAAA()这个对象销毁之后才销毁的。

 匿名函数的使用场景:

void Print_string(const string& st)
{
	cout << st << endl;
}

int main()
{
	string str("11111");  // 1
	Print_string(str);    // 2

	return 0;
}

上述的 代码 1 和  2 可以 使用匿名对象 写成一行代码:

Print_string(string("11111"));

此时就使用了 匿名对象 进行传参。

猜你喜欢

转载自blog.csdn.net/chihiro1122/article/details/130613818