c++(友元函数,静态成员)

一、友元:

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

友元函数并不是类中的一个成员
(1)注意:

a、友元函数可访问类的私有成员,但不是类的成员函数

b、友元函数不能用const修饰

c、友元函数可以在类定义的任何地方声明(除了在函数体内),不受类访问限定符限制(不是类的成员函数)

d、一个函数可以是多个类的友元函数

class Date
{
	friend ostream& operator<<(ostream& _cout, const Date &d); 
 public:
	Date(int year = 2943, int month = 243,int day = 2)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}
private:
	int _year;
	int _month;
	int _day;
};
class Time
{
	friend ostream& operator<<(ostream& _cout, const Date &d);//将日期内的友元声明在时间内的里面,说明,可以在日期内里面调用时间内的成员
public:
	Time(int hour, int minute, int second)
		:_hour(hour)
		, _minute(minute)
		, _second(second)
	{

	}
private:
	int _hour;
	int _minute;
	int _second;
};
ostream &operator<<(ostream &_cout, const Date&d)//此时cout作为左操作数,对象中的内容作为右操作数
{
	Time t(12,3,4);
	_cout << t._hour << "/" << t._minute << "/" << t._second;
	_cout << d._year << "/" << d._month << "/" << d._day;
	return _cout;//cout的生命周期比函数长,需要返回引用
}
void TestDate()
{
	Date d1(234, 5, 6);
	Date d2(d1);
	Date d3;
	cout << d3 << endl;
}

e、友元函数的调用与普通函数的调用和原理相同(友元函数不是类的成员函数,不需要通过对象来初始化,把对应的参数个数传过来即可。类的成员函数必须根据类的对象来进行调用。成员函数的参数比实际写出来的参数多一个

2、友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个 类中的非公有成员
3、优缺点:

a、优点:提高了程序运行效率(节省了函数调用和返回时的时间开销)

b、缺点:破坏了类的封装性和隐藏性(使类中给定的访问限定符如private不起作用,类中私有的成员在类外也可以访问,可以在友元函数中直接使用。)

4、a、友元关系不能继承

两个文件中定义两个类,互相包含(会引起头文件的重复包含),引用头文件或者从外部声明都会产生错误,我们可以把类中创建的另一个类对应的对象声明为一个指针,动态申请空间。如下:

Time.h中

class Date;
class Time
{
friend Date;
 public:
	Time(int hour, int minute, int second);
 private:
	int _hour;
	int _minute;
	int _second;
        Date *_d;
};

Time.cpp中:

#include"Time.h"
#include"Date.h"
#include<malloc.h>
Time::Time(int hour, int minute, int second)
		:_hour(hour)
		, _minute(minute)
		, _second(second)
	{
		_d = (Date*)malloc(sizeof(Date));
	}

Date.h中:

class Time;
class Date
{
  public:
	Date(int year = 2943, int month = 243,int day = 2);
        void PrintDate();
private:
	int _year;
	int _month;
	int _day;
        Time *_t;//看不到Time类,并不知道该类占几个字节,但是指针在32位平台下占4个字节。
};
在日期类的源文件动态从堆上申请一个对象中,把指针变为对象

Date.cpp中:

# include"Date.h"
#include"Time.h"
#include<malloc.h>
#include<iostream>
using namespace std;
Date::Date(int year = 2943, int month = 243,int day = 2)
		:_year(year)
		, _month(month)
		, _day(day)
	{
                _t=(Time*)malloc(sizeof(Time));//指针指向对象
	}
void Date::PrintDate()
{
     cout<<_year<<"/"<<_month<<"/"<<_day<<endl;
     cout<<_t->_hour<<_t->_minute<<_t->_second<<endl;
}

可以在时间类中访问日期类的私有成员变量;若想在日期类中访问时间类的成员变量,则在日期类中声明“friend Time;",让日期类成为时间类的友元。

 b、友元关系是单向的,不具有交换性

c、友元关系不能传递

一个类创建对象的个数?

a、count定义为局部变量,出了作用域函数就销毁,如下代码,结果为2,销毁只剩下主函数中创建的两个对象。

class Date
{
	//只有构造函数,拷贝构造函数才有可能创建对象
	//只有构造函数,拷贝构造函数和销毁对象时,个数才可能发生变化
public:
	Date()
		:_count(0)
	{
		_count++;
	}
	Date(Date& d)
		:_count(d._count++)//用d中的count把当前对象中的count拷贝出来
	{
		_count++;
	}
	~Date()
	{
		--_count;
	}
private:
	int _year;
	int _month;
	int _day;
	int _count;//计录创建对象的个数,都为整型
};
void TestDate()
{
	Date d3;
	Date d4(d3);
}
int main()
{
	Date d1;
	Date d2(d1);
	TestDate();
	return 0;
}

b、count定义为全局变量出了函数的作用域,会销毁,count变为0的情况(全局变量记录个数,每个对象可以共享,和对象没有任何关系)因为每个成员函数中都有,可以将其抽离出来,变为共享的。

int _count = 0;//共享的创建全局变量
class Date
{
	//只有构造函数,拷贝构造函数才有可能创建对象
	//只有构造函数,拷贝构造函数和销毁对象时,个数才可能发生变化
public:
	Date()
		:_count(0)
	{
		_count++;
	}
	Date(Date& d)
		:_count(d._count++)//用d中的count把当前对象中的count拷贝出来
	{
		_count++;
	}
	~Date()
	{
		--_count;
	}
private:
	int _year;
	int _month;
	int _day;
	int _count;//计录创建对象的个数,都为整型
};
void TestDate()
{
	 
}
int main()
{
	Date d1;
	Date d2(d1);
	Date d3;
	Date d4(d3);
	TestDate();
	return 0;
}

全局变量可以放到局部范围内修改,一修改就会导致结果不准确。使用全局变量不安全。 

void TestDate()
{
	_count = 0;
	Date d3;
	Date d4(d3);
}
int main()
{
	Date d1;
	Date d2(d1);
	TestDate();
	return 0;
}

执行到TestDate函数中的_count=0时,会把计数的结果变为0。

把计数的变量包含到成员变量中,每个成员函数都可以引用,也会导致统计结果不准确。 

完善以上代码,既需要一个整型的成员变量,又需要是被共享的(包含到每一个类对象中去),还需要这个变量在类对象中访问不了。采用static静态成员变量。

二、静态变量

声明为static的类成员(成员数据或成员函数)称为类的静态成员 ,静态成员变量必须先拿到类外进行定义,类中只相当于一个声明,编译器不会开辟空间。定义时必须和类有一定的关系。

1、特点:

a、静态成员为所有类对象所共享,不属于某个具体的实例

b、类静态成员即可用类名::静态成员或者对象.静态成员来访问

c、类静态成员变量必须在类外定义,定义时不添加static关键字

d、类的静态成员函数没有默认的this指针,因此在它里面不能使用任何 非静态成员

e、静态成员和类的普通成员一样,也有public、protected、private3 种访问级别,也可以具有返回值,const修饰符等参数

用静态变量完善一个类创建对象的个数?

a、

  class Date
{ 
public:
	Date()
		:_count(0)
	{
		_count++;
	}
	Date(Date& d)
		:_count(d._count++)//用d中的count把当前对象中的count拷贝出来
	{
		_count++;
	}
	~Date()
	{
		--_count;
	}
private:
	int _year;
	int _month;
	int _day;
	static int _count;//计录创建对象的个数,都为整型
};
 int Date::_count = 0;
void TestDate()
{
 	Date d3;
	Date d4(d3);
}
int main()
{
	Date d1;
	Date d2(d1);
	TestDate();
	return 0;
}

计数后结果为2

b、在局部范围内不能修改该变量,添加一句"d1._count=20;"编译后会报错,因为_count是类里面的静态成员变量,是类的成员,受访问限定符的限定,是私有的。在类外不能访问一个类的私有成员变量。如下会产生错误:

void TestDate()
{
 	Date d3;
	Date d4(d3);
	d1._count = 20;
}

c、把静态成员变量给成公有的,产看对象的地址是否相同

 class Date
{ 
public:
	Date()
		:_count(0)
	{
		_count++;
	}
	Date(Date& d)
		:_count(d._count++)//用d中的count把当前对象中的count拷贝出来
	{
		_count++;
	}
	~Date()
	{
		--_count;
	}
private:
	int _year;
	int _month;
	int _day;
public:
	static int _count;//计录创建对象的个数,都为整型
};
 int Date::_count = 0;
void TestDate()
{
 	Date d3;
	Date d4(d3);
}
int main()
{
	Date d1;
	Date d2(d1);
	cout << &d1._count << "==" << &d2._count << endl;
	TestDate();
	return 0;
}

结果打印的地址相等,说明创建的多个对象只有一个计数变量。

静态成员变量的大小加上和不加最后的成员的个数相同,可以通过在mian()中加入

cout<<sizeof(Date)<<endl;

说明静态成员变量不是每个类中都有一份,在整个类中只保存了一份。所有的类创建出的对象都可以去访问这个静态成员变量,是所有的成员共享的。类对象可以访问,但是不能包含在对象里面,不是对象里面的成员。可以通过在mian()中加入

cout<<Date::_count<<endl;

的方式输出(即加上类的作用域限定符)。

以下两种访问静态成员变量的方式都是正确的

Date d1;
Date d2(d1);
int d;
d=d1._count;
d=Date::_count;

2、静态成员变量给定的是私有的,不能直接从类外知晓类成员创建了多少成员变量。可以在类里面写一个共有的方法,获取;

 class Date
{ 
public:
	Date()
		:_count(0)
	{
		_count++;
	}
	Date(Date& d)
		:_count(d._count++)//用d中的count把当前对象中的count拷贝出来
	{
		_count++;
	}
	~Date()
	{
		--_count;
	}
	int GetCount()
	{
		return _count;
	}
private:
	int _year;
	int _month;
	int _day;
 	static int _count;//计录创建对象的个数,都为整型
};
 int Date::_count = 0;
void TestDate()
{
 	Date d3;
	Date d4(d3);
}
int main()
{
	Date d1;
	Date d2(d1);
 	TestDate();
	cout << d1.GetCount() << endl;
	return 0;
}

问题:其他函数在调用时,会新创建一个对象,使计数结果发生改变,不准确。

void TestDate()
{
	Date d1;
	Date d2(d1);
 	Date d3;
	Date d4(d3);
	cout << d1.GetCount() << endl;
}
void TestFunc()
{
	Date d;
	d.GetCount();
}

可以给函数加上static的方法,成为静态成员函数,不用通过对象来访问,直接加上类的作用域即可

class Date
{ 
public:
 Date()
  :_count(0)
 {
  _count++;
 }
 Date(Date& d)
  :_count(d._count++)//用d中的count把当前对象中的count拷贝出来
 {
  _count++;
 }
 ~Date()
 {
  --_count;
 }
  static int GetCount()
 {
  return _count;
 }
private:
 int _year;
 int _month;
 int _day;
  static int _count;//计录创建对象的个数,都为整型
};
 int Date::_count = 0;
void TestDate()
{
	Date d1;
	Date d2(d1);
 	Date d3;
	Date d4(d3);
	cout << d1.GetCount() << endl;
}
void TestFunc()
{
	Date d;
	d.GetCount();
}
int main()
{
 Date d1;
 Date d2(d1);
  TestDate();
 cout << d1.GetCount() << endl;// cout << Date::GetCount() << endl;
 return 0;
}

静态成员变量:

1)、静态成员遍量需要放在内外进行重定义,在类里面只能相当于一个声明

2)、静态成员变量是每一个类共享的,不是属于某一个对象,计算大小时只需要考虑非静态成员的大小

3、静态成员函数和普通成员函数的区别:

(1)普通成员函数里面,既可以访问普通成员变量、又可以访问静态成员变量(静态成员变量是所有的类共享的);
(2)在静态成员函数里面,不能访问普通成员变量。(静态成员函数中没有this指针,普通成员函数中有this指针,在调用时必须通过对象进行调用。
(2)调用约定的方式不同:静态成员函数的调用约定是_cdecl,c和c++中函数体默认的调用约定是_cdecl
(3)
不加static时,函数调用几次,构造函数就创建几次

class Test
{
public:
 Test()
 {
  cout << "Test()" << this << endl;
 }
};
void Fun()
{
 static int a = 12;
 a++;
 Test t;
}
int main()
{
 Fun();
 Fun();
 Fun();
 return 0;
}
加上static后,只调用了一次构造函数。只初始化了一次。
 
class Test
{
public:
 Test()
 {
  cout << "Test()" << this << endl;
 }
};
void Fun()
{
 static int a = 12;
 a++;
 static Test t;
}
int main()
{
 Fun();
 Fun();
 Fun();
 return 0;
}


只要一个对象创建好了,后面需要创建的对象可以直接拿来用,不需要进行重新创建。保证静态局部变量只有一份。调用时,只用调一次。
 
int g_val = 0;
void Fun()
{
 static int a = 12;
 a++;
 static Test t;
 if (0 == g_val)
 {
  Test();
  g_val = 1;
 }
}


编译期间,就把空间给出来了,但是没有执行构造函数。程序运行时,Test函数在第一次调用时,执行构造函数,把空间构造成一个对象。
 

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuruhua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值