目录
在C++中,static表示是静态的。类的静态成员函数、静态成员变量都是和类相关的,而不是和类的具体对象相关的,即使没有具体对象,也能调用类的静态成员函数和成员变量。const数据成员只是某个对象生存期内的常量,而对整个类来说是可变的。类可以创建多个对象,不同的对象其const成员的值可以不同。
一、类内的static和const
1、类内const成员初始化
const成员必须在定义的时候初始化,在类中是声明。对象实例化时会按初始化列表定义。
class yq { public: yq(int i = 10) :_i(i) {} private: const int _i; };
2、类内static成员初始化
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用 static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。(在使用时必须进行类外定义,否则报错。)
static类成员不能在初始化列表初始化。static成员变量在对象生成之前生成。初始化列表是在定义初始化一个对象的成员。而static类成员变量不属于。不能给缺省值,缺省值是给初始化列表的,静态成员变量不走初始化列表。
静态成员函数和静态成员变量,本质都是受限制的全局变量和全局函数,专属所在类,受类域和访问限定符的限制。计算类的大小的时候(sizeof(类)),不算静态变量。
c++规定:static成员类内声明,类外定义。即声明和定义分离。
-
静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。
-
静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明。
-
类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问。
-
静态成员函数没有隐藏的this指针,不能访问任何非静态成员。
-
静态成员也是类的成员,受public、protected、private 访问限定符的限制。
class Yq { Yq() {} private: static int _i; }; int Yq::_i = 0;
静态数据成员
-
静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
-
静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
-
静态数据成员可以被初始化,但是只能在类体外进行初始化,若未对静态数据成员赋初值,则编译器会自动为其初始化为 0。
-
静态数据成员既可以通过对象名引用,也可以通过类名引用。
3、类内static const成员初始化
在C++中,static const可以用来定义一个静态常量。
其中,static关键字表示该常量只在当前文件内可见,而不会被其他文件引用;const关键字表示该变量的值是不可修改的,即它是一个常量。
使用static const可以带来以下几点好处:
-
提高程序的效率。由于该常量是静态的,它被存储在程序的静态数据区中,只会在程序启动时被初始化一次,因此可以提高程序的运行效率。
-
避免命名冲突。由于static关键字的存在,同名的常量不会和其他文件的同名常量发生命名冲突,从而避免了错误的发生。
-
增加代码的可读性。由于const关键字的存在,该常量的值是不可变的,从而使得代码更加易于理解和维护。
例如,下面是一个使用static const定义静态常量的示例代码:
// 在头文件中定义一个静态常量 class MyClass { public: static const int MY_CONST; }; // 在源文件中初始化该静态常量 const int MyClass::MY_CONST = 100;
通过这种方式,我们可以在程序中使用MyClass::MY_CONST来访问这个常量。由于它是静态的,所以它只会被初始化一次,并且不会和其他文件的同名常量发生冲突。
二、类外的static和const
1、const
被const修饰的变量必须在定义时初始化。
应尽可能使用const
使用const可以避免无意中修改数据的编程错误。
使用const使函数能够处理const和非const实参,否则将只能接受非const数据。
使用const引用使函数能够正确生成并使用临时变量。
2、static
-
C++中的全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。
-
C++中,在函数或一个代码块内部声明的变量,称为局部变量。它们只能被函数内部或者代码块内部的语句使用。当局部变量被定义时,系统不会对其初始化,必须自行对其初始化。
在程序中,局部变量和全局变量的名称可以相同。但是在函数内的局部变量与全局变量是两个独立的变量,互不影响,全局变量的值可以在局部函数内重新赋值。
c/c++内存化为三个区域:栈区、堆区、静态区
-
栈区: 局部变量,形式参数(具有临时作用的变量)。特点:进入作用域创建,出了作用域销毁(还给操作系统)。
-
堆区: 动态内存分配。realloc malloc calloc free
-
静态区:全局变量静态变量。特点:创建好后,直到程序结束才销毁(还给操作系统)。
static修饰不同的变量
-
修饰局部变量– 称为静态局部变量 一个局部变量本来存放在栈区,但是被static修饰后存放在静态区。 static修饰局部变量改变了变量的存储类型(位置),使得该静态变量的生命周期变长,直到程序结束。
-
修饰全局变量– 称为全局变量 未被static修饰的全局变量具有外部链接属性,所有在其他源文件内部依然可以使用。(需要声明外部符号
extern ,例:extern int val_g;
)static修饰全局变量,改变了全局变量的链接属性,由外部链接属性变成了内部链接属性。这个静态变量只能在自己所在的源文件内部使用,不能在其他源文件内部使用。 -
修饰函数 – 称为静态函数 static修饰函数和static修饰全局变量是一样的。声明外部符号
extern int Add(int x,int y);
函数具有外部链接属性,但是被static修饰,就变成了内部链接属性。使得这个函数只能在自己所在的源文件内部使用,不能在其他文件的内部使用。
三、类内static和const的函数
1、const函数
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数 隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
- const对象可以调用const成员函数
- const对象不能调用非const成员函数
- 非const对象可以调用const成员函数
- 非const对象可以调用非const成员函数
- const成员函数不能调用非const成员函数
- 非const成员函数可以调用非const成员函数
void Date::Print()//此函数不能被const Date对象调用,调用时权限会扩大。 { //权限可以缩小,不能扩大。 cout << _year << "/" << _month << "/" << _day << endl; } void Date::Print() const//此函数才可以被const Date对象调用。 { //权限可以缩小,不能扩大。 cout << _year << "/" << _month << "/" << _day << endl; }
1、非const对象(成员函数)即可以调用const对象(成员函数),也可以调用非const对象(成员函数) 2、const对象(成员函数)只能调用const对象(成员函数),想调用非const对象(成员函数)就需要强转
const成员函数。const本质修饰*this。
成员函数定义原则:
-
能定义为const的成员函数都应该定义为const,这样const对象和非const对象都可以调用。
-
修改成员变量的函数不能定义为const
//Date.h class Date { void Print() const; } //Date.cpp void Date::Print()const { cout << _year << "/" << _month << "/" << _day << endl; } Date* operator&() { return this; } const Date* operator&() const { return this; }//若没有Date* operator&(),非const对象也可以调用此函数。此函数可以不写 //test.cpp void testConst() { const Date d1(2023, 10, 31); d1.Print();//若此函数不是const成员函数,则导致权限放大 Date d2; d2.Print(); }
类中变量分配内存在定义(Date d)时,在类中仅仅是声明。
2、static函数
static函数唯一能够访问的就是static变量或者其他static函数,且static函数属于所有对象共享,不具备this指针。但是,普通成员函数是可以调用static函数的。(补充:友元函数不具备this指针)
class Yq { public: static int getCount() { return _count; } private: static int _count; }; int Yq::_count = 1; int main() { cout << Yq::getCount() << Yq::getCount() << endl; }
静态成员函数
-
(1)静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。
-
(2)非静态成员函数有 this 指针,而静态成员函数没有 this 指针。
-
(3)静态成员函数主要用来方位静态数据成员而不能访问非静态成员。
总结:
-
(1)静态成员函数中不能调用非静态成员。
-
(2)非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。
-
(3)静态成员变量使用前必须先初始化(如 int MyClass::m_nNumber = 0;),否则会在 linker 时出错。