一、摘要

静态函数成员:

①:所有对象共享一个函数

②:静态成员函数只能访问静态成员变量

③:静态成员函数可以直接访问该类的静态数据和函数成员。但是,访问非静态成员,必须通过对象名。


二、静态函数成员的声明、定义与调用:

        首先,静态函数成员是类的一个成员,但它不属于类的任何一个对象实例,而是属于类本身。这就意味着,你可以直接通过类名来调用它,而不需要创建类的实例。

        使用静态函数成员的时候,你需要在类定义中,在函数声明前加上static关键字。例如:

class MyClass {
public:
    static void myStaticFunction() {
        // 函数实现
    }
};

在上面的代码中,myStaticFunction就是一个静态函数成员。

        调用静态函数成员时,你可以直接使用类名加上作用域解析运算符::,然后跟上函数名。例如

MyClass::myStaticFunction();

        由于静态函数成员不属于任何对象实例,因此它们不能访问类的非静态成员变量或非静态成员函数。但是,它们可以访问类的静态成员变量和其他静态成员函数

        另外,需要注意的是,静态函数成员在类的定义之外定义时,不能使用MyClass::前缀,因为此时类名还没有被完全定义。正确的做法是在类定义外部定义静态函数成员时,直接使用函数名,如下所示:

void MyClass::myStaticFunction() {
    // 函数实现
}

三、在类外定义静态函数成员

        在类外定义静态函数成员时,你需要遵循特定的格式。首先,你需要在类的定义中声明静态函数成员,然后在类的作用域之外提供这个函数的定义。注意,在定义时不需要再次使用 static 关键字,也不需要加上类名和作用域解析运算符 ::。

这里有一个简单的例子说明如何在类外定义静态函数成员:

// 类定义
class MyClass {
public:
    // 静态函数成员声明
    static void myStaticFunction();
};

// 类外定义静态函数成员
void MyClass::myStaticFunction() {
    // 静态函数成员的实现
    std::cout << "This is a static function of MyClass." << std::endl;
}

// 在main函数中调用静态函数成员
int main() {
    MyClass::myStaticFunction(); // 直接通过类名调用静态函数成员
    return 0;
}

在上面的代码中:

①:MyClass 类中声明了一个名为 myStaticFunction 的静态函数成员。
②:在类定义之外,我们提供了 myStaticFunction 的定义。这里使用了 MyClass:: 前缀来指明这个函数是属于 MyClass 类的。
③:在 main 函数中,我们直接通过类名 MyClass 调用了这个静态函数成员。

        需要注意的是,静态函数成员只能访问静态成员变量和其他静态成员函数。它们不能访问类的非静态成员变量或非静态成员函数,因为静态函数成员与任何特定的对象实例都不关联。

        在定义静态函数成员时,你不需要(也不应该)再次使用 static 关键字,因为 static 关键字已经在类定义中用于声明该函数为静态的了。你只需提供函数名和参数列表(如果有的话),并在函数体中实现所需的功能。

四、静态数据成员和静态函数成员的配套使用

        静态函数成员和静态数据成员可以配套使用,以实现一些特定的功能。静态数据成员是类的所有对象实例共享的变量,而静态函数成员则通常用于操作或访问这些静态数据成员。

以下是一个示例,展示了如何配套使用静态函数成员和静态数据成员:

#include <iostream>

class MyClass {
private:
    // 静态数据成员声明
    static int count;

public:
    // 构造函数,用于初始化对象时增加计数
    MyClass() {
        count++;
    }

    // 析构函数,用于销毁对象时减少计数
    ~MyClass() {
        count--;
    }

    // 静态函数成员,用于获取静态数据成员的值
    static int getCount() {
        return count;
    }

    // 静态函数成员,用于修改静态数据成员的值(注意:通常不建议这样做,除非有明确的理由)
    static void setCount(int newCount) {
        count = newCount;
    }
};

// 静态数据成员的定义和初始化
int MyClass::count = 0;

int main() {
    std::cout << "Initial count: " << MyClass::getCount() << std::endl;

    // 创建几个对象实例
    MyClass obj1;
    MyClass obj2;
    std::cout << "Count after creating two objects: " << MyClass::getCount() << std::endl;

    // 修改静态数据成员的值(通常应谨慎使用)
    MyClass::setCount(100);
    std::cout << "Count after setting it to 100: " << MyClass::getCount() << std::endl;

    // 销毁对象实例,计数应相应减少
    {
        MyClass obj3;
        std::cout << "Count inside block: " << MyClass::getCount() << std::endl;
    } // obj3 的生命周期结束,析构函数被调用,count 减少

    std::cout << "Count after obj3 is destroyed: " << MyClass::getCount() << std::endl;

    return 0;
}

在这个例子中:

①:MyClass 类有一个静态数据成员 count,用于跟踪创建的对象实例的数量。
②:构造函数和析构函数分别用于在创建和销毁对象时增加和减少 count 的值。
③:getCount 是一个静态函数成员,用于获取 count 的当前值。
④:setCount 是一个静态函数成员,用于设置 count 的新值(尽管在实际应用中,直接修改静态数据成员通常不是一个好的做法,除非有明确的理由)。

        静态数据成员 count 在类定义外部进行定义和初始化。由于它是静态的,它只存在一份拷贝,而不是每个对象实例都有一份。静态函数成员 getCount 和 setCount 则提供了访问和修改这个共享数据的接口。

        请注意,虽然这个例子展示了如何使用静态函数成员来修改静态数据成员的值,但在实际编程中,直接通过静态函数修改静态数据成员可能不是最佳实践。更好的做法是通过其他成员函数或方法来间接地修改静态数据成员,以确保数据的一致性和安全性。

五、通过对象调用静态函数成员

        在C++中,虽然技术上可以通过对象来调用静态成员函数,但这样做并不推荐,因为它会导致代码的可读性和维护性降低,容易使人误解静态成员函数的含义和用途。静态成员函数属于类本身,而不是类的实例对象,因此最好通过类名来调用它们。

        不过,如果你确实要用对象来调用静态成员函数,C++编译器并不会阻止你这样做。这是因为对象可以隐式地转换为指向其类型的指针,而静态成员函数可以通过类指针或对象指针来调用。下面是一个示例:

#include <iostream>

class MyClass {
public:
    static void myStaticFunction() {
        std::cout << "This is a static function." << std::endl;
    }
};

int main() {
    MyClass obj; // 创建一个MyClass的对象
    obj.myStaticFunction(); // 通过对象调用静态函数,虽然不推荐但可行
    MyClass::myStaticFunction(); // 推荐的方式:通过类名调用静态函数
    return 0;
}


        在这个例子中,obj.myStaticFunction() 和 MyClass::myStaticFunction() 都会输出同样的信息。然而,尽管这种方式在语法上是正确的,但它并不符合静态成员函数的语义。静态成员函数不依赖于任何特定的对象实例,因此最好始终通过类名来调用它们。

        如果你发现自己在通过对象调用静态成员函数,那么可能需要重新考虑你的设计决策。通常,如果你需要通过对象来调用某个函数,那么这个函数应该是非静态的成员函数。静态成员函数通常用于实现那些不依赖于对象状态的功能,比如工具函数或工厂函数。

        这样,你就可以在代码中使用静态函数成员了。记得,静态函数成员通常用于实现与类本身相关的功能,而不是与特定对象实例相关的功能哦。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐