友元和静态

一、友元

友元friend机制允许一个类授权其他函数访问它的非公有成员。

友元声明以关键字friend开头 ,它只能出现在类的声明中,它们不受其在类体中的public private和protected区的影响。

友元分为 外部函数友元、成员函数友元和类友元。

友元的特点:
1、不具有对称性:A是B的友元,并不意味着B是A的友元。

2、不具有传递性:A是B的友元,B是C的友元,但是A不是C 的友元。

3、不具有继承性:Base类型继承Object类型,如果Object类型是A的友元,并不意味着Base类型是A的友元。

1.1外部函数友元

class Int
{
private:
	int value;
public:
	Int(int x = 0) : value(x) {}
	~Int() {}
	friend Int operator+(const int x, const Int& it);
};
Int operator+(const int x,const Int& it)
{
	int val = x + it.value;
	return Int(val);
}
int main()
{
	Int a(10), b(20);
	Int c;
	c = 30 + a;
}

此时这个函数可以访问该对象的非公有成员。

1.2成员函数友元

class Test;
class Object
{
private:
	int value;
public:
	Object(int x) :value(x) {}
	~Object() {}
	void func(Test it)
	{
		it.sum += value;
	}
};
class Test
{
private:
	int sum;
public:
	Test(int x = 0) :sum(x) {}
	~Test() {}
};
int main()
{
	Object obj(10);
	Test test(20);
	obj.func(test);

}

首先来看这个程序,它有几处错误:

1.这一部分无法编译通过,这样写编译器会认为会有一个test实体对象,无法确定他占多少空间,所以会报错。可以把它变成引用。因为引用本质上是指针,这样系统就知道给它分配多少空间。

void func(Test it)

2.it.sum会报错,虽然这个类已经声明了,但是编译器 并不知道这个类里面有什么,sum对它来说是不可见的,所以会报错。但是我们如果将这个函数放在test类型定义之后,也还是编译不通过,这时候可以识别到test,但是这个函数无法访问test的私有成员。

所以这样才是正确的

class Object
{
private:
	int value;
public:
	Object(int x) :value(x) {}
	~Object() {}
	void func(Test& it);
};
class Test
{
private:
	int sum;
public:
	Test(int x = 0) :sum(x) {}
	~Test() {}
	friend void Object::func(Test& it);
};
void Object::func(Test& it)
{
	it.sum += value;
}
int main()
{
	Object obj(10);
	Test test(20);
	obj.func(test);

}

1.3类友元

这样改就是类友元:

class Test
{
private:
	int sum;
public:
	Test(int x = 0) :sum(x) {}
	~Test() {}
	friend class Object;
};
class Object
{
private:
	int value;
public:
	Object(int x) :value(x) {}
	~Object() {}
	void func(Test& it);
};

void Object::func(Test& it)
{
	it.sum += value;
}

注意:
友元不分公有私有还是保护,它自成一体

二、静态成员

2.1静态数据成员

由关键字static修饰类体中成员,成为类静态成员。类的静态成员为其所有对象共享,不管有 多少对象,静态成员只有一份存于公用内存中。静态数据成员被当作该类类型的全局对象。

全局对象和静态的区别
在多文件中,用static关键字修饰的变量只能在本文件中使用,而全局对象可以在其他文件中使用。

静态关键字可以修饰局部变量,全局变量,在.data区。当它第一次被调用,就会进行初始化,之后不会在进行初始化。在类中修饰成员函数时,静态是不具有this指针的,而且被所有成员所共享。而且在类中声明,类外定义 。

静态成员必须要在类外进行初始化,不能写在构造 函数中。

因为静态成员只用初始化一次。

在函数体内也不行,因为我们只声明了,并没有定义。

改成这样才可以:

 将上述代码中的num定义成公有的可以.访问,直接访问,但是不可以::num访问。

 

因为num是类域中的而不是全局域里面的。

class Object
{
private:
	int value;
	
public:
	static int num;
	Object(int x) :value(x) { num += 10; }
	~Object() {}
	void func() const;
};
int Object::num = 0;
int main()
{
	Object obja(10), objb(20), objc(30);
	sizeof(obja);//4字节
	cout << &obja.num << endl;
	cout << ::num << endl;
	Object::num = 100;

}

因为const修饰的是this指针,所以value不能进行修改。但是静态成员不具有this指针。 

2.2与模板结合

void func(int x)
{
	static int num = x;
	cout << "&num:" << &num << "num:" << num << endl;
	return;
}
int main()
{
	func(10); func(20);
}

静态num的值已经确定的,而且只有一个。

但是如果这样:

template<class T>
void func(T x)
{
	static int num = x;
	cout << "&num:" << &num << "num:" << num << endl;
	return;
}
int main()
{
	func(10); 
	func(12.23);
	func('a');
}

就会每一个都产生一个num

 

 2.3静态方法

非静态成员函数有this指针,静态成员函数没有this指针。

非静态成员函数既可以访问静态数据又可以访问非静态数据,但是静态成员函数只能访问静态数据,不可以访问非静态数据,原因还是因为没有this指针。

class Object
{
private:
	int value;
protected:
	static int num;
public:
	Object(int x) :value(x) {}
	~Object() { }
	void Print() const
	{
		cout << "value:" << value << endl;
		cout << "num:" << num << endl;
	}
	static void func();

};
int Object::num = 0;
void Object:: func()
{
	cout << "num:" << num << endl;
}

那么,这个函数可以编译通过吗?

都可以的。

那么静态量与静态常量有什么区别呢?

他们都可以在类内声明,类外定义。
 但是,静态常量可以直接在类内给初始值。但是静态量不行。(注意,这里的静态常量必须是整型

补充:类的设计不可以把自身设计进去(无线递归),但是可以设计静态的。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值