c/c++ static关键字详解
静态变量的生命周期是 程序开始到程序结束, 当程序开始时分配空间,结束时释放空间。 默认初始化为0。
注意:静态变量或静态函数只有在声明他的文件内使用,即要使用这个静态变量或静态函数必须包含声明它的头文件
而对于static关键字其中有三个比较明显的作用
1、static声明的变量的生命周期是程序开始到程序结束,作用域是声明他的那个块(文件,或者函数体)
// test.cpp 文件
#include <iostream>
int testA = 10;
// main.cpp文件
#include <iostream>
#include <stdio.h>
extern int testA; // 这个testA是test.cpp文件中的testA
void test()
{
static int a = 0; // 静态变量 声明周期是程序运行过程中,作用域是test()函数内, 另外static初始化只能初始化一次
for(int i = 0; i < 10; ++i)
{
a++;
}
std::cout << a << std::endl;// 将变量a 的值打印出来
}
int main()
{
test(); // 第一次调用打印结果是10
test(); // 第二次调用打印结果是20 因为是静态变量, 声明周期很长,所以a的值是按照上次数值10的基础上再相加的
std::cout << testA << std::endl;// 此时的testA的值是test.cpp文件中testA的值,打印结果是10 就是说全局变量的作用域是这个文件。
getchar();
return 0;
}
2、在类中的static成员变量,这个变量是有自己的内存空间,因此他被该类的所有实例所共享,如果修改,则该类的其他所有实例都能看到他的改变。
// main.cpp文件
#include <iostream>
#include <stdio.h>
class testA
{
private:
// 在类内声明静态变量
static int a;
std::string className;
public:
testA(std::string szName)
{
className = szName;
}
// 在控制台显示对象和静态变量的值
void show()
{
std::cout << className.c_str() << ":" << a << std::endl;
}
// 设置静态变量的值
void setAvalue(int value)
{
a = value;
}
};
// 类外初始化静态成员变量
int testA::a = 0;
int main()
{
testA a("a");
testA b("b");
a.show();
b.show(); // 以上两个show都是静态成员变量a的值0
a.setAvalue(5); // 此步更改了静态成员变量的值,因为静态成员变量的内存是单独的,被所有对象公用。所以下面打印出来的都是设置为5的值
printf("用对象a设置了静态成员的值之后\n");
a.show();
b.show();
getchar();
return 0;
}
3、同样在类中的static成员函数属于整个类所拥有,静态成员函数不接受this指针,因而他只能访问静态成员变量
// main.cpp文件
#include <iostream>
#include <stdio.h>
class testA
{
private:
// 在类内声明静态变量
static int a;
int b;
public:
static void showStatic()
{
std::cout << a << std::endl;
}
/*
// 这样写直接访问了类内的成员变量, 由于此函数是static成员函数不接收this指针,所以他找不到类的地址,所以也取不到对应的值。
static void show()
{
std::cout << b << std::endl;
}
*/
};
// 类外初始化静态成员变量
int testA::a = 0;
int main()
{
// 由于静态成员函数是被所有对象所共享的,所以不需要实例化 可以直接通过类名作用域调用静态成员函数
testA::showStatic();
getchar();
return 0;
}
c/c++ const关键字详解
const关键字的作用
1、所有变量加const关键字使这个变量成为只读变量,因为之后不能再被更改所以需要对它进行初始化
// main.cpp文件
#include <iostream>
#include <stdio.h>
// 加const修饰符
void testA(const int& a)
{
// a = 6;变量a不能赋值 因为前面加了修饰符const
std::cout << a << std::endl;
}
// 不加const修饰符
void testB(int& a)
{
a = 6; // 此时变量没有加修饰符, 所以是可以更改变量a的值的
std::cout << a << std::endl;
}
int main()
{
int a = 0;
testA(a); // 打印结果是0
printf("调用testA之后\n");
std::cout << a << std::endl; // 打印结果是0
testB(a); // 打印结果是6
printf("调用testB之后\n");
std::cout << a << std::endl; // 打印结果是6
getchar();
return 0;
}
2、对于指针,可以制定指针本身为const,也可以制定指针指向的数据为const,或两者同为const
// main.cpp文件
#include <iostream>
#include <stdio.h>
int main()
{
int a = 3;
int b = 4;
// 此时指针没有加const修饰符可以更改p的指向,也可以更改p指向的数据
int* p = NULL;
p = &a; // 将指针指向a的地址
std::cout << *p << std::endl; // 打印结果是3
p = &b; // 将指针的指向更改为b的地址
std::cout << *p << std::endl; // 打印结果是4
*p = 10; // 将指针p指向的地址的数据更改
std::cout << *p << std::endl; // 打印结果是10
int const* p1 = NULL; // 此时加了一个修饰符 他修饰的是*p1 即p1指向的地址的数据不能更改
p1 = &a; // 将指针指向a的地址
std::cout << *p1 << std::endl; // 打印结果是3
p1 = &b; // 将指针p1的指向更改为b的地址
std::cout << *p1 << std::endl; // 打印的结果是10 因为上面已经将b值更改所以打印结果是10
// 此时的指针p1 如果你操作*p1 = 4 这样就错误了 因为const修饰了*p1 所以*p1是不能更改的
int *const p2 = &a; // 此时const修饰了指针p2 就是指针的指向不能更改, 但是可以更改p2指向的地址的数据
*p2 = 3; // 这样可以操作
std::cout << *p2 << std::endl; // 打印结果是3
// 但p2 = &b 这种操作就是错误的了
int const* const p3 = &a; // 此时即不能更改指针的指向 也不能更改指针指向的地址的数据
// 即不能 p2 = &b; *p2 = 10 这两种操作都是错误的
getchar();
return 0;
}
3、对于类的成员函数,若指定为const类型,则标明其是一个常函数, 不能修改类的成员变量
// main.cpp文件
#include <iostream>
#include <stdio.h>
class testA
{
public:
testA(int b)
{
a = b;
}
void test (int c)const
{
// 此时此函数是常函数 他不能修饰类内的所有成员 所以不能按下面的操作
// a = c; 这种操作就是错误的
std::cout << a << std:: endl;
}
private:
int a;
};
int main()
{
testA a(3);
a.test(5);
getchar();
return 0;
}