C++ class中的静态(static)成员
(1) 静态数据成员
①一般地静态数据成员在该类定义之外被初始化,如同一个成员函数被定义在类定义之外一样。在这种定义中的静态成员的名字必须被其类名限定修饰,例如下面是_interestRate的初始化
// 静态类成员的显式初始化
#include "account.h"
double Account::_interestRate = 0.0589;
②静态数据成员的初始化不应该被放在头文件中,而应该放在含有类的非inline 函数定义的文件中。静态数据成员可以被声明为任意类型。例如:
#include <string>
class Account
{
// ...
private:
static const string name;
};
const string Account::name( "Savings Account" );
作为特例,整型的const 静态数据成员可以在类体中用一常量值初始化。例如,如果决定用一个字符数组而不是string 来存储账户的姓名那么我们可以用int 型的const 数据成员指定该数组的长度,例如:
// 头文件
class Account {
// ...
private:
static const int nameSize = 16;
static const char name[nameSize];
};
// 文本文件
const int Account::nameSize; // 必需的成员定义
const char Account::name[nameSize] = "Savings Account";
用常量值作初始化整型的const 静态数据成员是一个常量表达式(constant expression)。如果需要在类体中使用这个被命名的值,那么,类设计者可声明这样的静态数据成员。例如,因为const 静态数据成员nameSize是一个常量表达式,所以类的设计者可以用它来指定数组数据成员name 的长度。在类体内初始化一个const 静态数据成员时,该成员必须仍然要被定义在类定义之外。但是因为这个静态数据成员的初始值是在类体中指定的所以在类定义之外的定义不能指定初始值。
因为name 是一个数组,不是整型,所以它不能在类体内被初始化。任何试图这么做的行为都会导致编译时刻错误,例如:
class Account {
// ...
private:
static const int nameSize = 16; // ok: 整型
static const char name[nameSize] =
"Savings Account"; // 错误
};
name 必须在类定义之外被初始化。
这个例子还说明了一点我们注意到成员nameSize 指定了数组name 的长度,而数组name的定义出现在类定义之外
const char Account::name[nameSize] = "Savings Account";
nameSize 没有被类名Account 限定修饰。尽管nameSize 是私有成员,但是name的定义仍没有错。如同类成员函数的定义可以引用类的私有成员一样,静态数据成员的定义也可以。静态数据成员name的定义是在它的类的域内,当限定修饰名Account::name被看到之后,它就可以引用Account 的私有数据。
③静态数据成员的访问
1. 在类的成员函数中可以直接访问该类的静态数据成员,而不必使用成员访问操作符:
inline double Account::dailyReturn()
{
return( _interestRate / 365 * _amount );
}
2. 在非成员函数中,我们必须以如下两种方式访问静态数据成员:
I. 使用成员访问操作符
class Account {
// ...
private:
friend int compareRevenue( Account& , Account* );
// 余下部分未变
};
// 引用和指针参数来说明对象和指针访问
int compareRevenue( Account &ac1, Account *ac2 )
{
double ret1, ret2;
ret1 = ac1._interestRate * ac1._amount;
ret2 = ac2->_interestRate * ac2->_amount;
// ...
}
ac1._interestRate 和ac2->_interestRate都引用静态成员Account::_interestRate
II. 访问静态数据成员的另一种方法,是用被类名限定修饰的名字直接访问它
// 用限定修饰名访问静态成员
if ( Account:_interestRate < 0.05 )
当我们不通过类的成员访问操作符访问静态数据成员时必须指定类名以及紧跟其后的域操作符Account:: 。
因为静态成员不是全局对象所以我们不能在全局域中找到它下面的friend 函数compareRevenue()的定义与刚刚给出的等价
int compareRevenue( Account &ac1, Account *ac2 )
{
double ret1, ret2;
ret1 = Account::_interestRate * ac1._amount; //因为是friend函数,才可以访
//私有的静态成员变量_interestRate
ret2 = Account::_interestRate * ac2->_amount;
// ...
}
注意:静态数据成员的“惟一性”本质(独立于类的任何对象而存在的惟一实例),使它能够以独特的方式被使用,这些方式对于非static 数据成员来说是非法的
①静态数据成员的类型可以是其所属类,而非static 数据成员只能被声明为该类的对象的指针或引用。例如:
class Bar {
public:
// ...
private:
static Bar mem1; // ok
Bar *mem2; // ok
Bar mem3; // 错误
};
2 静态数据成员可以被作为类成员函数的缺省实参,而非static 成员不能。例如:
extern int var;
class Foo {
private:
int var;
static int stcvar;
public:
// 错误: 被解析为非 static 的 Foo::var
// 没有相关的类对象
int mem1( int = var );
// ok: 解析为 static 的 Foo::stcvar
// 无需相关的类对象
int mem2( int = stcvar );
// ok: int var 的全局实例
int mem3( int = ::var );
};
(2) 静态成员函数
使用类的静态成员函数来访问类的私有静态数据成员。
静态成员函数的声明除了在类体中的函数声明前加上关键字static, 以及不能声明为const 或volatile之外,与非静态成员函数相同。出现在类体外的函数定义不能指定关键字static。
静态成员函数没有this 指针,因此在静态成员函数中,隐式或显式地引用这个指针都将导致编译时刻错误。试图访问隐式引用this 指针的非静态数据成员也会导致编译时刻错误。例如前面给出的成员函数dailyReturn()就不能被声明为静态成员函数,因为它访问了非静态数据成员amount。
我们可以用成员访问操作符点. 和箭头-> 为一个类对象或指向类对象的指针调用静态成员函数,也可以用限定修饰名直接访问或调用静态成员函数,而无需声明类对象。
(3)在派生类中的静态数据成员与静态成员函数
class的static data member只有一份实例,被class和class的派生类的所有实例共享。class和class的派生类共用同一块内存中的静态数据成员。
一个简单的例子:
#include <iostream>
using namespace std;
class A{
public:
A(){}
~A(){}
static void SetA(int b){a=b;}
static int GetA(){return a;}
private:
static int a;
};
int A::a = 5;
class B : public A{
public:
B(){}
~B(){}
};
int main(){
cout<< "a=" << A::GetA() <<'/n'; //输出5
cout<< "a=" << B::GetA() <<'/n'; //输出5
B::SetA(4);
cout<< "a=" << B::GetA() <<'/n'; //输出4
cout<< "a=" << A::GetA() <<'/n'; //输出4
return 0;
}
类的静态函数与函数中的静态数据成员在编译期绑定!
分享到:
相关推荐
C++的static关键字可修饰类成员变量/方法,表示变量/方法不从属于特定对象,而是属于类的。仔细琢磨静态成员变量,会发现其与C++的方式既相容也矛盾,具有特殊性。 先说相容的一面。·C/C++·有声明和定义的说法:...
C++中静态成员函数访问非静态成员的实例 实现代码: #include /* 静态成员函数只能访问静态数据成员、静态成员函数和类以外的函数和数据,不能访问非静态数据成员,但静态成员函数或静态数据成员可由任意访问许可...
大家都知道C++中类的成员函数默认都提供了this指针,在非静态成员函数中当你调用函数的时候,编译器都会“自动”帮你把这个this指针加到函数形参里去。当然在C++灵活性下面,类还具备了静态成员和静态函数,即 ...
在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省...
static void xxx_fun() //静态成员函数 { ... } } 普通成员变量每个对象都有各自的一份,静态成员变量所有对象共享。 普通成员函数每个对象都有各自的一份,静态成员函数所有对象共享,内存只有一份。 静态...
类体中的数据成员的声明前加上static关键字,该数据成员就成为了该类的静态数据成员。和其他数据成员一样,静态数据成员也遵守public/protected/private访问规则。同时,静态数据成员还具有以下特点: 1.静态数据...
在类范围中声明数据成员,但在文件范围内执行定义。这些静态类成员具有外部链接。下面的示例阐释了这一点: // static_data_members.cpp class BufferedOutput { public: // Return number of bytes written by ...
在网上搜集的关于C++类的静态成员的使用方法,希望对初学者有帮助!
类的静态成员 静态成员变量 存储在 全局数据区 #include class Test { private: ///静态成员变量访问权限 static int c1; public: static int GetC1() { return c1; } static void SetC1(int i) { c1=i; } void ...
《C++ 基类中静态成员初始化问题、基类头文件中定义类外变量重定义问题的解决过程》博客附带代码,供需要看的朋友下载,很简单,一般不用下载。
C++的静态成员不仅可以通过对象来访问,还可以直接通过类名来访问。 class CBook{ public: static double price;//需要通过类外来进行初始化 } int main(void){ CBook book; book.price;//通过对象来访问 CBook...
原因很简单大家都知道,静态成员函数不能访问非静态成员,这是因为静态函数属于类而不是属于整个对象,静态函数中的 member可能都没有分配内存。静态成员函数没有隐含的this自变量。所以,它就无法访问自己类的非...
在C++中,一般使用静态成员来代替C语言的全局变量,以达到数据共享。C和C++的全局变量有一定的局限性,可以任意被修改,也容易和其它的变量名冲突,故在C++中,一般不使用全局变量。 静态数据成员必须进行初始化,...
记住:通常静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域操作符来指出静态成员所属的类.但如果静态成员是整型或是枚举型const,则可以在类声明中初始化!!! 代码如下:#include ...
然而从本质上来说类的静态成员函数的函数形参中没有默认的this指针,导致不能调用具体实例对象的成员。 下面我们来测试一下: 先在静态成员函数中调用静态成员变量: #include using namespace std; class vpoet {...
C++ 静态成员的类内初始化详解及实例代码 一般来说,关于C++类静态成员的初始化,并不会让人感到难以理解,但是提到C++ 静态成员的”类内初始化”那就容易迷糊了。 我们来看如下代码: //example.h #include #...
(针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针. ) 请看示例程序四( <effective c++ (2nd)> (影印版)第59...
我们都知道C++ class中有三种成员函数,static(静态的),nonstatic(非静态的),virtual(虚拟的)各种成员函数的指针各有差别,下面是一个完整的样例:(注意红颜色的差别) class A { public: static void ...
2. 操作符重载,this,静态成员 Overloading Operators. this. Static members 3. 类之间的关系 Relationships between classes: friend. Inheritance 4. 虚拟成员,抽象,多态 Virtual Members. Abstraction. ...
第二大题: 1. 在面向对象语言中,接口的多种不同的实现方式即为多态。多态性是允许你将父对象设置成为一个或更多的他的子对象相等...而且静态成员变量在对象实例化之前就可以进行赋值,说明静态成员函数不在对象内部。