目录
编辑
static成员
static性质简介
static属于整个类,属于所有对象
static成员的声明与定义
static函数
友元friend
友元特性简介
友元关系讲解
内部类
特性一
特性二
匿名对象
结语
static成员
static性质简介
static成员在类里面是非常独特的,因为这个成员并不存在于类里面,就像是函数一样
我们先来看这么一段程序:
class A
{
public:int _a;static int _b;
};int main()
{A aa1;cout << sizeof(aa1) << endl;return 0;
}
我们能看到,这段程序的目的就是看这个类的大小,我们的类里面有一个普通的int成员和一个static成员,但是结果为 4,这说明static成员是不存在于类中的
static属于整个类,属于所有对象
这句话的意思就是,我们无论创建了多少个对象,所有的对象想要用这个static成员,那么使用的就都是同一个static成员,因为这个static成员属于所有对象
我们可以验证一下这个特性,来看这么一段代码:
ps:该段代码中有关于static成员声明与定义的问题和static成员函数的问题,稍后会讲到
class A
{
public:A(){_b++;}~A(){_b--;}//静态成员函数static int get_b(){return _b;}private:int _a;static int _b;//声明
};int A::_b = 0;//定义int main()
{A aa1;A aa2;A aa3;A aa4;cout << A::get_b() << endl;return 0;
}
我们能看到,每个对象创建出来时,都会调用对应的构造函数,而我们在构造函数里面就干一件事:将静态成员++
又因为所有对象共用同一个static成员,所以我们每创建一个对象,我们的_b就会++一下
最后,我们再通过静态成员函数将静态成员变量取出,就能看到具体此时有几个对象还存在了
static成员的声明与定义
因为是static成员,所以是不能在构造函数中进行初始化的
那我们可以按如下方式赋值吗?
private:int _a = 0;static int _b = 0;
答案是否定的,因为这里的值是给初始化列表看的,但是我们的static成员都不在类里面,所以这种方法是行不通的
而静态成员的其中一个特性就是——静态成员变量必须在类外面初始化
而类中的只是声明,而类外面的是定义,定义时不加关键字static,但是需要指定类域,如下:
class A
{
private:int _a;static int _b;
};int A::_b = 0;
static函数
如果我们将static成员定义为私有,那我们就无法在类外面使用该成员
由此,C++里就搞出了一个static函数,如下:
class A
{
public:static int get_b(){return _b;}private:int _a;static int _b;
};int A::_b = 0;
如上,我们写了一个函数get_b,通过将这个函数设为公有我们就能取到_b
并且由于这个函数是static函数,所以没有this指针,也就无法访问到除了静态成员以外的其他成员
友元friend
友元特性简介
当一个类A有特殊情况,必须要访问类B中的私有成员时,我们就可以使用友元
如下:
class A
{friend class B;int _a = 1;
};class B
{
public:int getnum(){return _t._a;}
private:A _t;
};int main()
{B b1;cout << b1.getnum() << endl;return 0;
}
我们能看到,类A中的_a是私有的,这就意味着其他类是无法使用的,但是我们可以将类B设置为类A的友元,这样子我们的类B就能访问到类A的私有成员了
添加友元的方式就是在类的声明前面加一个friend
当然还有函数的友元,如下:
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;
}
istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}
如上是我们在上文中讲到的Date类(日期类),如若有不了解的,可以点下面链接复习一下:
Date 日期类的实现
和友元类差不多,都是声明前面加一个friend
友元关系讲解
这里关系到一个问题,我们可以联系现实:
我喜欢你,你就一定得喜欢我吗?
我把你当朋友,你就一定得把我当朋友吗?
我是你爸的朋友,我就一定得是你的朋友吗?
这几句话就讲解了:友元关系不是相互的,我把你当朋友,你可以用我的东西,但是我不一定能用你的东西,除非你把我当成朋友
同时,友元关系是不能继承的,这个知识点了解就好,这关系到以后会讲的继承章节的相关内容
内部类
内部类相对来说比较简单
我们在一个类里面,能定义一个int变量,能定义一个static变量,同样的,我们也可以定义一个类类型的变量,也就是在类里面定义一个类
特性一
class A
{int _a = 0;static int _s;class B // 内部类{int _k;void getAnum(const A& a){cout << _s << endl;cout << a._a << endl;}};};
int A::_s = 0;
如上,我们可以总结出内部类的其中一个特性:
内部类天生就是外部类的友元,即内部是外部的朋友,所以内部类可以使用外部类的私有
但是外部类不是内部类的友元,所以外部类不能使用内部类的私有
也就是:不是我把你当朋友,你就一定得把我当朋友
特性二
我们再来看这么一段代码:
class A
{int _a = 0;static int _s;class B // 内部类{int _k;void getAnum(const A& a){cout << _s << endl;cout << a._a << endl;}};};
int A::_s = 0;int main()
{A a1;cout << sizeof(a1) << endl;return 0;
}
我们可以看到,对类A的大小进行统计以后发现,类B是不计在类A里面的
由此我们可以得出第二个特性:
内部类和外部类是两个平行的类,内部类唯一的特殊点就是受到类域的限制和天生友元关系
也就是说,这两个类之间并没有说谁大谁小,都是两个一样的类,只不过需要访问内部类的话就需要对类域进行限制,如下:
A a1;
A::B _b;
匿名对象
我们来看这么一个例子(假设有一个类A已存在):
A a1; //有名对象
A(); //匿名对象
匿名对象和有名对象的区别在于:有名对象的生命周期是当前域结束时才到
但是匿名对象的生命周期是他所在的那一行,也就是即用即销毁
我们来看下面这一段代码:
class A
{
public:A(){cout << "A()" << endl;}~A(){cout << "~A()" << endl;}
};int main()
{A a1;A();A a2;return 0;
}
我们可以明显看到,匿名对象那里是刚声明完就销毁了,而有名对象是直到程序结束了才销毁
至于匿名对象的好处,就是调用起来会更省事
现在看起来可能会觉得没什么用,但是当我们在学习STL相关知识的时候就能体会到真香定律(bushi
举个栗子:
#include<map>int main()
{map<int, int> m1;//使用有名对象的插入方式pair< int, int> s1(1, 2);m1.insert(s1);//使用匿名对象的插入方式m1.insert(pair<int, int>(1, 2));//使用隐式类型转换为匿名对象的插入方式m1.insert({ 1,2 });return 0;
}
map是stl中的一个数据结构,而我们每次插入数据都需要插入一个pair类型的数据进去
如果是有名对象的话,我们就需要将pair类型的变量定义出来再插入进去(s1)
但如果是匿名对象的话,我们直接在插入里面定义一个匿名对象,即用即销毁也无所谓,反正数据插入进去了
当然还有更好的方法,就是走隐式类型转换,当然这些显然有点超纲,我们只需要知道匿名在未来的学习中非常常见即可
结语
距离上一篇更新已经过去了三个月整了,这三个月一直忙于C++和算法,现在也算是抽出时间来补一补博客了,突然有种高中知识学完了但发现初中的作业还没写完的感觉(苦笑)
如果感觉这篇博客对各位有帮助的话,希望可以多多支持喔!!!