为什么在 class 声明之外不允许使用 virtual 和 static 关键字?

Why virtual & static keywords aren't allowed outside class declaration?

我很想知道为什么 C++ 中不允许以下内容?

第一个节目:

#include <iostream>
class Test {
    public:
        int myfun();
}
virtual int Test::myfun()
{ return 0; }
int main()
{ }

[错误] 'virtual' 在 class 声明之外

第二期节目:

#include <iostream>
class Test {
    public:
        int myfun();
};
static int myfun() {
    std::cout<<"This program contains an error\n";
    return 0; 
}
int main() {
  Test::myfun(); 
  return 0; 
}

[错误] 无法调用没有对象

的成员函数'int Test::myfun()'

那么,我的问题是

为什么我不能像第一个程序那样将成员函数设为虚函数?

为什么我不能像第二个程序那样使成员函数静态化?

是否有任何理由不允许 class 之外的这 2 个关键字?

您想通过在 class 声明之外声明来创建一个函数 virtual。但是,请考虑将使用您的 class 的其他代码。您很可能 #include 只有 Test class 的 header,它只包含 class Test 块,而不包含实现。因此,在编译该代码时,编译器将不知道函数是 virtual。但是,它需要知道,因为它需要为 virtual 和非 virtual 函数生成不同的调用代码。

在更详细的情况下,假设一个比您的示例更高级的程序。根据您的提议,它将包含几个编译单元并进行组织,例如,如下(为清楚起见省略了#ifdef 守卫):

// Test.h
class Test {
    public:
        int myfun();
};

// Test.cpp
#include "Test.h"
virtual int Test::myfunc() { return 0;}

// other.cpp
int foo(Test& test) { return test.myfunc(); } // <--- *

您将 Test.cppother.cpp 分开编译。所以当你编译 other.cpp 时,编译器如何知道它应该在 foo() 中执行对 test.myfunc() 的虚拟调用?

同样的推理适用于 static 函数。但是,请注意 static 关键字还有另一个含义,即 可以 在 class 声明之外使用。

virtual 与多态有关,这就是为什么它只允许在 class 中使用。 static 允许在 classes 之外并生成全局函数 "private"。您的程序的问题是 class Test 中的 myfun() 不是静态的,您必须创建一个 Test 实例来调用此方法。

int main()
{
    Test test;
    test.myfun(); // works
    return 0;
}

myfun() 的静态版本与 class 无关,不能像这样调用:Test::myfunc()(因为,正如我所说,它与测试无关) .您可以这样调用它:

int main()
{
    myfun(); // global function, has nothing to do with any classes
    return 0;
}

修饰符必须在函数声明上,否则无法调用只给定声明的函数。

因为它们必须在声明中,所以将它们也放在定义中是多余的。没有特别好的理由禁止它们(只要它们符合声明),但也没有特别好的理由允许它们。

编译器一次编译一个源文件("translation unit")。如果你要声明一个 class

#include "Test.h"

class SpecialTest : public Test {
    int myfun();
};

编译器只看到 "Test.h" 中的内容,而不是 "Test.cpp" 中的内容。因此,如果只允许在 .cpp 文件中生成 myfun() virtual,编译器将无法在不查看 "Test.cpp"

的情况下正确编译 "SpecialTest"

如评论中的 juanchopanza 所示,虚拟仅在对象 class 的上下文中才有意义。回想一下,虚拟方法是一个没有实现的函数,将其留给其他 class 继承自定义虚拟方法的 class 。但是如果虚定义在class之外,这种情况下如何表达继承呢?这将是一个未实现的功能,其他 classes 不可能实际实现它。

对于静态,您混淆了它在 class 上下文内外的含义。如果你想拥有一个不需要相应对象就可以调用的函数,你可以将它定义为class的静态函数。如果您希望此函数位于 class 之外,只需省略 static,因为该函数无需对象即可使用。但是 class 上下文之外的静态意味着完全不同的东西。