第5章 数据的共享与保护
5-7定义一个Cat类,拥有静态数据成员 numOfCats,记录Cat的个体数目;静态成员函数getNumOfCats(),读取numOfCats。设计程序测试这个类,体会静态数据成员和静态成员函数的用法。
#include<iostream>
using namespace std;
class cat{
public:
cat()
{
numOfCats++;
}
static int getNumOfCats()
{
return numOfCats;
}
~cat()
{
numOfCats--;
}
private:
static int numOfCats;
};
int cat::numOfCats = 0; //类的静态成员变量必须在类外进行初始化
void numprintf()
{
cout<<"There are "<<cat::getNumOfCats()<<" cats alive!"<<endl;
}
int main()
{
cat a;
cat b;
cat c;
numprintf();
cat *t1,*t2;
t1=new cat();
t2=new cat();
numprintf();
delete t1;
numprintf();
return 0;
}
注:静态数据成员numOfCats用来给cat类的对象个数进行计数,其被cat类的所有对象共同维护和使用,数据共享。
在类外可通过“类名::静态数据成员标识符”调用静态数据成员,而且类的静态成员变量必须在类外进行初始化,不能在类内进行初始化。
5-11 在一个文件中定义一个全局变量n,主函数main(),在另一个文件中定义函数fn1(),在main()中对n赋值,再调用fn1(),在fn1()中也对n赋值,显示n最后的值。
//main文件
#include<iostream>
using namespace std;
#include"fn1.h" //声明头文件
int n;
int main()
{
n=0;
fn1();
cout<<"n的值:"<<n<<endl;
return 0;
}
//另外建一个名为fn1.h的头文件
extern int n; //声明外部变量n
int fn1()
{
n=5;
}
头文件fn1.h里有外部变量n,用extern关键字加以声明,这个外部变量是可以为多个源文件共享的全局变量。
PS:main文件中声明需要的文件名称需要和调用的文件名称一致,一一对应,才能调出需要的内容。
5-12 在函数fn1()中定义一个静态变量n,fn1()中对n的值加1,在主函数中,调用fn1()十次,显示n的值。
#include<iostream>
using namespace std;
void fun1()
{
static int n = 0; //静态变量
n++;
cout<<n<<endl;
}
int main()
{
for(int i = 0 ;i < 10 ; i++)
{
fun1();
}
return 0;
}
函数fn1()中的静态变量n会保持上一回的值,即使发生调用,也不会为该变量建立新的副本,即每次调用该函数时,不会重复初始化为0,会使用上一次保存的值,该变量会在各次调用之间共享。
5-13 定义类X、Y、Z,函数h(X*),满足:类X有私有成员i,Y的成员函数g(X*)是X的友元函数,实现对X的成员i加1,类Z是类X的友元类,其成员函数f(X*)实现对X的成员i加5,函数h(X*)是X的友元函数,实现对X的成员i加10。在一个文件中定义和实现类,在另一个文件中实现main()函数。
//main文件
#include<iostream>
using namespace std;
#include"xyz.h"
int main()
{
X d;
d.show();
Y d1;
d1.g(&d);
d.show();
Z d2;
d2.f(&d);
d.show();
h(&d);
d.show();
return 0;
}
//另外建一个名为xyz.h的头文件
#ifndef XYZ_H
#define XYZ_H
class X;
class Y
{
public:
void g(X* p);
};
class Z
{
public:
void f(X* p);
};
class X
{
public:
X():i(0){}
friend void Y::g(X* p);
friend class Z;
friend void h(X* p);
void show()
{
cout<<i<<endl;
}
private:
int i;
};
void Y::g(X* p)
{
p->i++;
}
void Z::f(X* p)
{
p->i += 5;
}
void h(X* p)
{
p->i += 10;
}
#endif // XYZ_H
代码解释:
- 头文件“xyz.h”中 #ifndef #define #endif条件编译指令用途:防止头文件被多次定义,需用唯一的标识符来标记某文件是否已参加过编译,保证头文件中定义的变量不存在重复声明或定义。标识符一般大写来防止与其他变量冲突,便于区分。
- 友元关系提供了不同类或对象之间的数据共享机制,从字面意思也可以看出来,像“朋友”一样,开了一个绿色通道,让函数g(X*)、f(X*)、h(X*)能访问到类X的私有成员i。
- 还需要注意的,友元函数并不属于这个类本身,故这个类本身的对象是无法访问到这些友元函数的。
- 无论是友元函数还是友元类。都不能使用类内的this指针,同时也不可以被继承,如同父亲的朋友不一定是儿子的朋友这个道理。
5-14 定义Boat与Car两个类,二者都有weight属性,定义二者的一个友元函数totalWeight(),计算二者的重量和。
#include <iostream>
using namespace std;
class car;
class boat{
private:
int weight;
public:
boat(int w){weight = w;}
friend int gettotalweight(boat &b, car &c);
};
class car{
private:
int weight;
public:
car(int w){weight = w;}
friend int gettotalweight(boat &b, car &c);
};
int gettotalweight(boat &b, car &c){
return b.weight+c.weight;
}
int main()
{
boat b1(5);
car c2(2);
cout<<"Totalweight:"<<gettotalweight(b1,c2)<<endl;
return 0;
}
PS:
- 友元函数的形式:只需要在类内对这个函数进行声明,并在之前加上friend关键字。
- 友元函数gettotalweight的形参boat &b, car &c,这里&地址符的作用是引用的功能,通过地址改变对象的数据,传引用的好处是省去了复制,节约了空间和时间,提高了效率。
- 另外,定义友元函数gettotalweight()时需要前向引用声明,声明另一个需要用到的类class car,使编译器知道还有这样一个类,才不会编译错误。
本专栏为本人大二C++课程的习题作业和一些学习经验的分享,供大家参考学习。如有侵权请立即与我联系,我将及时处理。
参考书籍为:C++语言程序设计 第五版 -清华大学出版社- 郑莉,董渊、C++语言程序设计 第五版 -清华大学出版社- 郑莉,董渊(学生用书)
编译环境:Visual Studio 2019、Dev-C++
欢迎关注我的微信公众号,分享一些有趣的知识:程序猿的茶水间