我很想知道为什么在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;没有对象
所以,我的问题是
为什么我不能像第一个程序那样使成员函数虚拟化?
为什么我不能像第二个程序那样使成员函数静态化?
有没有理由在课外不允许这两个关键字?
答案 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类中有意义。回想一下,虚方法是没有实现的函数,将其留给从定义虚方法的类继承的其他类。但是如果虚拟定义在一个类之外,那么在这种情况下如何表达继承?它将是一个未实现的函数,没有其他类实际实现它的可能性。
对于静态,你会在类的上下文之外和之内混淆它的含义。如果想要一个可以在不需要相应对象的情况下调用的函数,可以将其定义为类的静态函数。如果你希望这个函数在类之外,那么只需省略静态函数就可以使用而无需任何对象。但是类上下文之外的静态意味着完全不同的东西。