为什么在 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.cpp
与 other.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 上下文之外的静态意味着完全不同的东西。
我很想知道为什么 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.cpp
与 other.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"
如评论中的 juanchopanza 所示,虚拟仅在对象 class 的上下文中才有意义。回想一下,虚拟方法是一个没有实现的函数,将其留给其他 class 继承自定义虚拟方法的 class 。但是如果虚定义在class之外,这种情况下如何表达继承呢?这将是一个未实现的功能,其他 classes 不可能实际实现它。
对于静态,您混淆了它在 class 上下文内外的含义。如果你想拥有一个不需要相应对象就可以调用的函数,你可以将它定义为class的静态函数。如果您希望此函数位于 class 之外,只需省略 static,因为该函数无需对象即可使用。但是 class 上下文之外的静态意味着完全不同的东西。