C++(11)——静态成员

回顾:我们都知道C中的静态在修饰局部变量或函数和全局变量时是不太一样的。

  • 局部变量可见性在其所在函数内部,并将其存储到.data区,在函数运行时只初始化一次,其生存期也会被延长,因此可以以引用方式返回。
  • 如果将函数或全局变量定义为静态,其生存期不会改变,仍然分别存放在代码区.data区,但其只在定义它的文件中可见,同一个工程的其他文件不可见。

静态数据成员

在C++中静态数据成员有如下特点:

  1. 在构造函数和拷贝构造函数中不能对静态数据成员进行列表方式构建,也就是不能在参数列表中对其进行初始化(在这两个函数体内部对其进行操作不能称之为初始化)
  2. 必须在类外初始化,初始化方式为:类型名 类名::变量名 = 0;
  3. 重要的一点:在类中的静态数据成员是所有类共享的数据成员,比如下面的代码:
class Object
{
public://这里主要是为了方便访问
	int value;
	static int num;
public:
	Object(int x = 0) :value(x)
	{
		num += 1;
	}
	Object(const Object& obj) :value(obj.value)
	{
		num += 1;
	}
	~Object()
	{
		num -= 1;
	}
};
int Object::num = 0;
int main()
{
	Object a(10);
	Object b(20);
	cout << &a.value << "  " << &a.num << endl;
	cout << &b.value << "  " << &b.num << endl;
}

运行结果如下:
在这里插入图片描述
我们可以看到两个对象的num数据成员地址相同,因此类中的静态数据成员是所有类共享的数据成员。
因此作为公有的静态数据成员,我们既可以用对象访问它,比如:a.num +-= 10;也可以用类型名访问它,Object::num = 100;

但是大多数情况下数据成员我们都会设计为私有,此时在类外的语句难道不会报错吗?
不会,因为编译器会会认为那只是一个初始化语句,并不是一条执行语句,在进入主函数之前编译链接就已经完成了这部分工作,因此下面的代码依旧正确。

class Object
{
private:
	int value;
	static int num;
public:
	Object(int x = 0) :value(x)
	{
		num += 1;
	}
	Object(const Object& obj) :value(obj.value)
	{
		num += 1;
	}
	~Object()
	{
		num -= 1;
	}
};
int Object::num = 0;

解决下一个问题:在该类的常方法中,能否对num进行修改?

void Print() const
{
	num += 10;//ok
	cout<<"value:"<<value<<"num:"<<num<<endl;
}

答案是可以的,因为num作为一个静态数据成员,他不属于任何类,因此也就没有this指针,在常方法内部的编译过程中,不会添加this指针,不会对其产生任何约束,因此也就可以对其进行修改。

静态成员函数

看下面的代码,这个静态成员函数是否可以完成其中的操作?

class Object
{
private:
	int value;
	static int num;
public:
	Object(int x = 0) :value(x)
	{
		num += 1;
	}
	Object(const Object& obj) :value(obj.value)
	{
		num += 1;
	}
	~Object()
	{
		num -= 1;
	}
	static int show()
	{
		num += 10;
		cout<<"value:"<<value<<endl;//error,编译器报错:非静态成员引用必须与特定对象关联
		cout<<"num:"<<num<<endl;//ok
		
		return num;
	}
};
int Object::num = 0;

答案是不可以的。
其实普通的成员函数既可以访问普通成员(非静态成员),也可以访问静态成员。
但是静态成员函数的一大特点就是:编译器在编译过程中只会标识它是哪一个类的静态成员函数,并不会添加this指针,没有this指针,所以只能够访问静态成员,不能够访问非静态成员。

同理,静态函数可以通过类名直接访问,也可以通过变量名直接访问。

因此上述的静态成员函数也不可声明为常方法,因为在编译过程中就没有this指针。

问题:静态函数有没有办法访问到非静态成员呢?

答案是可以的,因为静态函数可以设计成带参类型,参数是该对象的引用,在函数体内访问或者操作非静态成员,此时既可以通过对象名对非静态成员进行访问,也可以通过类名加上作用域解析符来访问类中的非静态成员,看下面的代码:

class Object
{
private:
    int value;
    static int num;
public:
    Object(int x = 0):value(x){}
    static void Show(Object & obj)
    {
        obj.value += 10;
        cout<<obj.value<<endl;
        cout<<num<<endl;
    }
};

int Object::num = 10;

int main()
{
    Object obja(10);
    Object objb(10);
    obja.Show(obja);
    obja.Show(objb);
    Object::Show(objb);
    return 0;
}

运行结果如下:成功地通过静态成员函数访问到了非静态数据成员
在这里插入图片描述

辨析下列程序哪一个可以编译通过?

A

class Object
{
public:
	int value;
	Object obj;
};

这个无法编译通过,因为会形成递归创建过程,无穷递归下去

B

class Object
{
public:
	int value;
	Object & obj ;
};

这个也无法编译通过,因为在构建原对象时,obj必须引用一个已经存在的对象,无法做到
C

class Object
{
public:
	int value;
	Object *pobj;
};

这个可以编译通过,因为这个指针即便没有指向任何对象,后期也可以认为修改
D

class Object
{
public:
	int value;
	static Object obj;
};

这个也可以编译通过,因为静态成员不属于对象,任何对象都不会有内部对象

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值