【问题标题】:Why virtual & static keywords aren't allowed outside class declaration?为什么在类声明之外不允许使用虚拟和静态关键字?
【发布时间】:2015-05-22 12:13:07
【问题描述】:

我很想知道为什么 C++ 中不允许跟随?

第一个节目:

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

[错误] 'virtual' 外部类声明

第二个程序:

#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()'

所以,我的问题是

为什么我不能像第一个程序一样使成员函数成为虚拟函数?

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

有什么理由不允许这两个关键字出现在课堂之外?

【问题讨论】:

  • static 绝对允许在类定义之外。但想想virtual 的真正含义。
  • 有理由允许这两个课外吗?你想达到什么目标?
  • @meet:第二个程序定义了第二个同名的非成员函数。由于您没有定义Test::myfun,它将无法链接。
  • @Jarod42:这些示例尝试将修饰符添加到不在其声明中的定义中。
  • 函数的定义必须与其声明相匹配,因此我不太明白你的意思。如果允许,您认为您会得到什么?

标签: c++ syntax static virtual


【解决方案1】:

修饰符必须在函数声明中,否则无法调用仅给出声明的函数。

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

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

      你想通过在类声明之外声明这个函数来创建一个函数virtual。但是,请考虑将使用您的类的其他代码。您很可能将#include 仅包含Test 类的标题,该类仅包含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(); } // <--- *
      

      您将与other.cpp 分开编译Test.cpp。那么当你编译other.cpp时,编译器怎么知道它应该对foo()中的test.myfunc()进行虚拟调用呢?

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

      【讨论】:

        【解决方案4】:

        编译器一次编译一个源文件(“翻译单元”)。如果你要声明一个类

        #include "Test.h"
        
        class SpecialTest : public Test {
            int myfun();
        };
        

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

        【讨论】:

          【解决方案5】:

          正如 cmets 中的 juanchopanza 所指出的,virtual 仅在上下文 ob 类中才有意义。回想一下,虚方法是没有实现的函数,将其留给从定义虚方法的类继承的其他类。但是如果虚定义在一个类之外,这种情况下如何表示继承呢?这将是一个未实现的功能,其他类不可能实际实现它。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-09-16
            • 2010-09-19
            • 2015-02-20
            • 2021-08-02
            • 1970-01-01
            • 2018-08-15
            相关资源
            最近更新 更多