类外static函数定义要不要加static关键字?

发布时间 2023-08-25 12:00:59作者: 石中火本火

类外static函数定义要不要加static关键字?

先说答案:不需要

错误代码:

#include<iostream>
#include<memory>
using namespace std;

class Base {
public:
    enum class Type {
        Derived1,
        Derived2,
        Derived3
    };
    static Base* create(Type type);
};

class Derived1 : public Base {
public:
    static Base* create() {
        cout<<"new 1"<<endl;
        return new Derived1();
    }
};

class Derived2 : public Base {
public:
    static Base* create() {
        cout<<"new 2"<<endl;
        return new Derived2();
    }
};

class Derived3 : public Base {
public:
    static Base* create() {
        cout<<"new 3"<<endl;
        return new Derived3();
    }
};

static Base* Base::create(Type type) {  // 此处不应加static关键字
    switch (type) {
        case Type::Derived1:
            return Derived1::create();
        case Type::Derived2:
            return Derived2::create();
        case Type::Derived3:
            return Derived3::create();
        default:
            return nullptr;
    }
}

int main(){
    Base* obj = Base::create(Base::Type::Derived1);
    return 0;
}

编译报错:
image

这段代码的目的是使用工厂模式,在基类的static函数中,根据输入参数选择不同的派生类对象来返回。

在这里static成员函数是无法在类内直接定义的,这与static无关,只是因为在函数中使用到了在下方定义的派生类,编译为顺序编译,所以无法找到下面的派生类的声明,所以只能在类外定义。

报错解释:

报错意思是:

无法声明该成员函数具有静态链接。静态链接属性是指函数在编译时被链接到程序的静态存储区域,而不是在运行时动态链接到程序的堆栈中。这意味着该函数的内存地址在程序运行期间是固定的,不会随着函数的调用而改变。这与静态成员函数的目的相同,那为什么不可以如此声明呢?StackOverflow上解答如下:

The keyword static has several different meanings in C++, and the code you've written above uses them in two different ways.

In the context of member functions, static means "this member function does not have a receiver object. It's basically a normal function that's nested inside of the scope of the class."

In the context of function declarations, static means "this function is scoped only to this file and can't be called from other places."

the compiler interpreted the static here to mean "I'm implementing this member function, and I want to make that function local just to this file." That's not allowed in C++ because it causes some confusion: if multiple different files all defined their own implementation of a member function and then declared them static to avoid collisions at linking, calling the same member function from different places would result in different behavior!

即如果在多个文件里定义相同的静态成员函数,它们都是仅对本文件有效的。他们会链接到不同的静态区地址。而正常的静态成员函数只有一个地址,不管哪个对象从何处调用都是调用的同一个静态成员函数,这就会导致调用时的不同行为产生,C++不允许这样做,所以报错说:我们不允许你定义一个静态链接。但我们已经声明了静态链接,编译器后续就会知道这个定义是一个静态成员函数的定义

解决方案

只需要去除定义中的static即可,在声明中标注static关键字已经足够。