[C++]学习C/C++中的静态

一、使用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
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FL1768317420

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值