c++中的静态成员
c++类中的静态成员的用法是个难点,下面对c++类中静态成员做个总结,希望有困惑的朋友能够从中有所收获。
类中的静态成员包括静态成员变量和静态成员函数,静态成员是属于整个类的而不是某个对象,静态成员存储一份供所有对象使用。
一、静态数据成员
类中的数据成员加上static关键字,数据成员就变成了静态数据成员。静态数据成员也遵守public/private/protected等访问属性。静态成员在类体内声明,如下程序所示
class Tan
{
private:
static int age;//静态变量的声明
string name;
};
int Tan::age = 25;//静态变量的定义(初始化) 不受访问属性的限制
下面介绍几点静态数据成员的特性
1、c++的静态数据成员被类的所有对象所共享,包括该类的派生类的对象,即父类对象与子类对象共享父类的静态数据成员。
class Tan
{
public:
static int age;//静态变量的声明
};
int Tan::age = 25;
class T:public Tan
{
};
void main()
{
Tan tan;
cout<<tan.age<<endl;
T tt;
cout<<tt.age<<endl;
}
2、c++类中的静态数据成员可以作为成员函数的默认实参,普通数据成员则不行,非static数据成员不能独立于对象而使用。
class Tan
{
private:
static int num;
int score;
public:
void set(int i = num);
};
int Tan::num = 25;
void Tan::set(int i)
{
cout<<"num = "<<i<<endl;
}
void main()
{
Tan tan;
tan.set();
}
3、c++静态数据成员的类型可以是所属类的类型而普通数据成员则不可以,普通数据成员只能声明为所属类类型的指针或引用。
class Tan
{
private:
static Tan num;//正确
Tan score;//错误
Tan *point;//正确
Tan &tan;//正确
};
4、静态数据成员的值在const成员函数中可以被修改
class Tan
{
private:
int static num;
int score;
mutable int age;
public:
void set()const;
Tan(int tt)
{
age = tt;
}
};
int Tan::num = 25;
void Tan::set()const
{
++num;//正确
cout<<"num"<<num<<endl;
++age;//正确
cout<<"num"<<age<<endl;
++score;//error 普通数据成员不能被const成员函数修改
cout<<"num"<<score<<endl;
}
void main()
{
Tan tan(19);
tan.set();
}
5、可以利用类中的私有静态成员函数初始化(定义)静态数据成员。
定义static数据成员的方式:先指定类型名,接着是成员的完全限定名。如类中一静态数据num,它是float类型,属于类Tan。则定义就是:float Tan:: num = 26.0; 这里我们直接使用了常量26.0作为初始化式。static成员的定义是在类作用域中,所以我们可以直接把静态成员函数作为初始化式来初始化数据成员(此时静态成员函数不受访问属性的限制)
class Tan
{
private:
static int num;
static int set(int n);
public:
void show()
{
cout<<"num ="<<num<<endl;
}
};
int Tan::num = set(5);
int Tan::set(int n)
{
return n;
}
void main()
{
Tan tan;
tan.show();
}
6、静态成员变量的访问,直接在下面的程序中讲解
class Tan
{
public:
static int num;
int age;
Tan():age(3){};
public:
void show()
{
cout<<"num ="<<num<<endl;
cout<<"age ="<<age<<endl;
}
};
int Tan::num = 6;
void main()
{
Tan tan;
cout<<Tan::num<<endl;//right
cout<<Tan::age<<endl;//error
tan.show();
}
静态成员数据的访问和普通成员数据基本一样。唯一不同的一点在于静态数据成员不属于任何一个类对象,它是属于整个类,当静态数据成员为public,我们可以直接Tan::num访问它,而普通数据成员就不可以。
注意:静态数据成员使用之前,必须初始化,否则在linker时候会出错,
二、静态成员函数
静态成员函数和普通成员函数的本质区别在于静态成员函数没有this指针,普通成员函数有一个指向当前对象的this指针。这样静态成员函数不与任何对象相联系。
静态成员函数和普通成员函数的本质区别在于静态成员函数没有this指针,普通成员函数有一个指向当前对象的this指针。这样静态成员函数不与任何对象相联系。
静态成员函数的声明与定义
在类定义体内,普通成员函数的声明前面加上关键字static就是静态成员函数的声明。静态成员函数的定义可以在类的内部也可以在类的外部定义静态成员函数但此时无需保留static关键字。
#include <iostream>
#include <string>
using namespace std;
class Tan
{
private:
static int num;
public:
static void show()
{
cout<<"num="<<num<<endl;
}
static void set();
};
int Tan::num = 6;
void Tan::set()//此时无需保留关键字static
{
num = num + 100;
}
//void main()
//{
// Tan tan;
// tan.show();
// // tan.set();
// tan.show();
//}
void main()
{
Tan::show();
Tan::set();
Tan::show();
}
静态成员函数的访问和普通成员函数基本类似,但是静态成员函数可以Tan::show(),但是普通成员函数不可以,原因和上面讲的静态成员数据访问一样。
下面介绍几点静态成员函数的特性
1、可以通过类名调用静态成员函数如Tan::show()但是不可以调用非静态成员函数。
2、静态成员函数中不能调用非静态成员
3、在类的非静态成员函数中使用静态成员
<span style="font-size:18px;">#include <iostream>
#include <string>
using namespace std;
class Tan
{
private:
static int num;
int age ;
public:
void show()
{
cout<<"num="<<num<<endl;
}
void show1()
{
set();
}
static void set();
};
int Tan::num = 6;
void Tan::set()
{
cout<<"num="<<++num<<endl;
}
void main()
{
Tan tan;
tan.show();//非静态成员函数使用静态数据成员
tan.show1();//非静态成员函数使用静态成员函数
}</span>
4、静态成员函数地址可用普通函数指针储存,而普通成员函数地址需要用类成员函数指针来储存。
class Tan
{
private:
static int num;
int age ;
public:
Tan():age(25){};
void show()
{
cout<<"age ="<<age<<endl;
}
void show1()
{
set();
}
static void set();
};
int Tan:: num = 6;
void Tan::set()
{
cout<<"num="<<num<<endl;
}
void main()
{
Tan tan;
void(*point1)() = &tan.set;//这样的也可以,调试过
void(*point1)() = &Tan::set;//静态成员函数地址使用普通函数指针存储
(*point1)();//直接调用 就可以直接访问相应的静态成员函数了
}
对于类中的普通成员函数需要使用类成员函数指针来储存的相应实现代码,没有搞清楚,所以就没写了,有知道的朋友请指教一二。
5、静态成员函数不可以同时声明为virtual、const、volatile函数
class Tan
{
public:
virtual static void show();//error
static void set()const;//error
static void func()volatile;//error
};
static成员不是任何对象的组成部分,所以static成员函数不能被声明为const、virtual、volatile等形式函数。比如,将成员函数声明为const就是承诺不会修改该函数所属的对象。