一、使用static关键字
C/C++中有静态变量、静态函数、静态数据成员、静态成员函数,但是没有静态类。
(一)变量
静态变量,意味着其生命周期从程序开始运行到程序结束。
1.局部静态变量。定义在函数中,只初始化一次,不像普通的局部变量,会随着某次函数调用的结束而消失。
2.全局静态变量。作用域被限制在定义它们的程序文件中(即别的程序文件不能用这个变量),初始值为0。在多人开发项目时,为了防止与他人命令变量重名,可以将变量定位为 static。
#include <stdio.h>
int n;
void fn(void)
{
n = 5;
}
void fn_static(void)
{
static int n = 10;
n++;
printf("static n=%d\n", n);
}
int main(void)
{
printf("global n=%d\n", n);
fn();
printf("global n=%d\n", n);
fn_static();
fn_static();
return 0;
}
(二)函数
函数用static,意味着作用域被限制在定义它们的程序文件中(即别的程序文件不能用这个函数),比如
static void innerMessage();
在多人开发项目时,为了防止与他人命令函数重名,可以将函数定位为 static。
(三)数据成员
静态数据成员是指该类的所有对象所共有的数据成员,从而实现数据共享。
静态数据成员可以用"类名."的方式直接访问,也可以通过“对象.”的方式进行访问。
静态数据成员必须要类内定义,类外初始化。
#include<iostream>
using namespace std;
class ClassName
{
public:
static int val;//定义静态数据成员val
};
int ClassName::val;//静态数据成员初始化,前面不加static,以免与一般静态变量或对象相混淆。
int main()
{
ClassName obj;//创建对象
cout << "obj.val=" << obj.val << " or ClassName.val=" << ClassName.val<<endl;
return 0;
}
静态数据成员可以作为成员函数的默认形参,而普通数据成员则不可以。静态数据成员在const函数中可以修改,而普通的数据成员是不能修改的!
#include <iostream>
#include <string>
using namespace std;
class Test{
static int a;
int b;
public:
void fun_1(int i = a); //right
//void fun_2(int i = b); //这里报错,默认形参必须先先于类的对象而建立,因此要静态数据成员
void test()const{
a++; //right
// b++;//(wrong)const pointed you can't change data of the object who called it
cout << "a=" <<a << " b=" << b<<endl;
}
};
int Test::a;
int main()
{
Test test;
test.test();
return 0;
}
(四)成员函数
静态成员函数可以作为工具类函数,用于执行一些通用的操作,如字符串处理、数学计算等,不需要实例化对象即可使用。静态成员函数内不能访问非静态成员。
#include <iostream>
#include <string>
using namespace std;
class Point{
public:
static double output(){
//printf("%d\n",m_x); //静态成员函数中不能直接使用非静态的数据成员,因为不能确定是哪个对象的数据成员
return 1.2345;
}
private:
int m_x;
};
int main()
{
Point pt;
cout << pt.output() << endl;
cout << Point::output() << endl;
return 0;
}
二、未使用static关键字——静态绑定和动态绑定(Static and Dynamic Binding)
绑定,简而言之,是将一个名称(如变量、函数等)与其所在的内存地址关联起来。这种关联可以在编译时(静态)或运行时(动态)确定。
静态绑定也被称为早期绑定 (Early Binding)。动态绑定也被称为后期绑定或运行时绑定,在运行时根据指针或引用所指向的对象类型来选择调用哪个函数,从而实现动态多态性。
1.普通的变量和函数都是静态绑定
2.函数重载(Overloading)是静态绑定
函数重载是指在声明多个名称相同但参数列表不同的函数,这些的参数可能个数或顺序、类型不同,但是不能靠返回类型来判断。特征是:
- 函数名字相同;
- 参数不同;
- virtual 关键字可有可无(注:函数重载与有无virtual修饰无关);
- 返回值可以不同。
#include<iostream>
using namespace std;
// 函数重载示例
void display(int i) {
cout << "Here is int: " << i << endl;
}
void display(double d) {
cout << "Here is double: " << d << endl;
}
int main() {
display(5); // 调用 int 版本的 display
display(5.5); // 调用 double 版本的 display
return 0;
}
3.函数指针能实现动态绑定
#include <iostream>
int add(int x, int y)
{
return x + y;
}
int subtract(int x, int y)
{
return x - y;
}
int multiply(int x, int y)
{
return x * y;
}
int main()
{
int x;
std:: cout << "Enter a number : ";
std::cin >> x;
int y;
std::cout << "Enter another number: ";
std::cin >> y;
int op;
do
{
std::cout << "Enter an operation (0=add, 1=subtract, 2=multiply): ";
std::cin >> op;
} while (op < 0 || op > 2);
// Create a function pointer named pFcn (yes, the syntax is ugly)
int (*pFcn)(int, int);
// Set pFcn to point to the function the user chose
switch (op)
{
case 0: pFcn = add; break;
case 1: pFcn = subtract; break;
case 2: pFcn = multiply; break;
}
// Call the function that pFcn is pointing to with x and y as parameters
// This uses late binding
std::cout << "The answer is: " << pFcn(x, y) << 'n';
return 0;
}
4.函数重定义(redefined)是静态绑定
redefined是指子类重新定义父类的非虚函数。特征是:
- 不在同一个作用域(分别位于子类与父类) ;
- 函数名字相同;
- 返回值可以不同;
- 不管参数是否不同,父类的同名函数将被隐藏。
#include<iostream>
using namespace std;
class Base {
public:
void show1(){
cout << "Base1 class" << endl;
}
void show2(int flag) {
cout << "Base2 class" <<flag<< endl;
}
};
class Derived : public Base {
public:
void show1(){
cout << "Derived1 class" << endl;
}
void show2(double flag){
cout << "Derived2 class" <<flag<< endl;
}
};
int main() {
Base* ptr = new Derived();
ptr->show1();
ptr->show2(1);
ptr->show2(1.1);
delete ptr;
Derived dobj;
dobj.show1();
dobj.show2(1);
dobj.show2(1.1);
return 0;
}
运行结果为:
Base1 class
Base2 class1
Base2 class1
Derived1 class
Derived2 class1
Derived2 class1.1
5.函数重写(overridden)是动态绑定
overridden是指子类重新定义父类的虚函数。特征是:
- 函数名字相同;
- 参数相同;
- 父类函数必须有 virtual 关键字,不能有 static ;
- 返回值相同,否则报错。
#include<iostream>
using namespace std;
class Base {
public:
virtual void show() {
cout << "Base1 class" << endl;
}
void show1(){
cout << "Base2 class" << endl;
}
};
class Derived : public Base {
public:
void show() {
cout << "Derived1 class" << endl;
}
void show1(){
cout << "Derived2 class" << endl;
}
};
int main() {
Base* ptr = new Derived();
ptr->show(); // 函数重写是动态绑定
ptr->show1(); // 函数重定义是静态绑定
delete ptr;
Derived dobj;
Base* ptr1 = &dobj;
ptr1->show();// 函数重写是动态绑定
ptr1->show1();// 函数重定义是静态绑定
Base bobj = dobj;
bobj.show(); //注意这里没有了动态绑定
bobj.show1();
return 0;
}
运行结果是:
Derived1 class
Base2 class
Derived1 class
Base2 class
Base1 class
Base2 class