为什么虚拟&静态关键字不允许在类声明之外?

时间:2015-05-22 12:13:07

标签: c++ syntax static virtual

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

第一个节目:

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

[错误]&#39;虚拟&#39;外类声明

第二节目:

#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; 
}

[错误]无法调用成员函数&#39; int Test :: myfun()&#39;没有对象

所以,我的问题是

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

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

有没有理由在课外不允许这两个关键字?

5 个答案:

答案 0 :(得分:6)

修饰符必须在函数声明上,否则只能在声明的情况下调用函数。

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

答案 1 :(得分:4)

virtual与多态有关,这就是为什么它只允许在一个类中。 static被允许在课外,并使全局函数&#34;私有&#34;。您的程序的问题是,类myfun()中的Test不是静态的,您必须创建一个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;
}

答案 2 :(得分:1)

您希望通过在类声明之外声明来创建函数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(); } // <--- *

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

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

答案 3 :(得分:0)

编译器一次编译一个源文件(&#34;翻译单元&#34; )。如果你要宣布一个班级

#include "Test.h"

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

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

答案 4 :(得分:0)

正如评论中的juanchopanza所示,虚拟只在上下文ob类中有意义。回想一下,虚方法是没有实现的函数,将其留给从定义虚方法的类继承的其他类。但是如果虚拟定义在一个类之外,那么在这种情况下如何表达继承?它将是一个未实现的函数,没有其他类实际实现它的可能性。

对于静态,你会在类的上下文之外和之内混淆它的含义。如果想要一个可以在不需要相应对象的情况下调用的函数,可以将其定义为类的静态函数。如果你希望这个函数在类之外,那么只需省略静态函数就可以使用而无需任何对象。但是类上下文之外的静态意味着完全不同的东西。