有没有办法不继承“虚拟性”?子类中的函数?
在 C++ 中是否可以让一个类重写虚函数,但仅在通过超类调用该函数时才进行虚拟分派(即,在静态类型的子类上调用该函数时不进行虚拟分派)?我知道事实并非如此,但是有什么方法可以实现接近的目标吗?
想要这个的原因是我有两个类都公开了一个flush()函数。在我的程序中,绝大多数时间,我直接在我知道其类型的子类对象上调用 flush()
,因此不需要虚拟调度。然而,我想添加一个超类到混合中,这样我就可以很少将对其中一个类的实例的引用传递到 doSomethingThenFlush() 函数中,该函数将调用flush( ) 实际上。
我知道我可以使用模板而不是虚拟函数,并且我知道我可以有两个不同的函数(例如,flushVirtual()
,它只是调用flushNonVirtual()
,并调用< code>flushNonVirtual() 在任何地方我不需要虚拟调度)。但这些看起来都有点像在一个主要是语法问题上抛出代码。有没有更优雅的方法来实现这一目标?
也许更重要的是,有人知道为什么 C++ 中继承了虚拟性吗?
struct Base
{
virtual ~Base(){}
virtual void func();
};
struct Derived : public Base
{
void func(){}
};
void callVirtually(Base &base)
{
base.func();//this will use virtual dispatch
}
void callStatically(Derived &derived)
{
derived.func();//I don't want/need this to use virtual dispatch
}
int main()
{
Derived derived;
callVirtually(derived);
callStatically(derived);
}
Is it possible in C++ to have a class override a virtual function, but only have virtual dispatch when the function is called through the superclass (ie. not when it is called on something statically typed as the subclass)? I know this isn't what happens, but is there any way to achieve something close?
The reason for wanting this is that I have two classes which both expose a flush()
function. The vast majority of the time in my program, I am calling flush()
directly on a subclass object that I know the type of, so I don't need virtual dispatch. However I want to add a superclass into the mix so that very infrequently I can pass a reference to an instance of either one of the classes into a doSomethingThenFlush()
function, which would call flush()
virtually.
I know I could use templates instead of virtual functions, and I know I could have two different functions (eg. flushVirtual()
which just called flushNonVirtual()
, and call flushNonVirtual()
everywhere I don't need virtual dispatch). But these both seem a bit like throwing code at a problem which is largely syntactical. Is there any more elegant way to achieve this?
Perhaps more importantly, does anyone know why virtualness is inherited in C++?
struct Base
{
virtual ~Base(){}
virtual void func();
};
struct Derived : public Base
{
void func(){}
};
void callVirtually(Base &base)
{
base.func();//this will use virtual dispatch
}
void callStatically(Derived &derived)
{
derived.func();//I don't want/need this to use virtual dispatch
}
int main()
{
Derived derived;
callVirtually(derived);
callStatically(derived);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
虚拟性是继承的,因为您不知道是否有人会从您的
Derived
进一步派生。有人也可以创建一个MoreDerived
,它可以传递给一个需要Derived&
的函数,当他们发现它是Derived 时,他们会感到难过
的所有虚拟函数版本均被调用为 bieng,而不是MoreDerived
的版本。如果您的意思是您永远不会从
Derived
继承,因此您不想为虚拟函数调用付费,那么您就不走运了,因为 C++ 没有提供任何方法来保证您永远不会从类继承,而这对于执行您想要的操作是必要的。Virtualness is inherited because you don't know if someone is going to derive further from your
Derived
. Someone could just as well make aMoreDerived
which could be passed to a function expecting aDerived&
, and they'd be sad when they found that it wasDerived
's versions of all your virtual functions were bieng called instead ofMoreDerived
's.If you mean that you won't ever inherit from
Derived
so you don't want to pay for a virtual function call, then you're out of luck, because C++ provides no way to promise that you won't ever inherit from a class, which would be necessary to do what you are wanting.在 C++03 中,没有。
正如其他人所说,这是一种编译器优化(也是一种经常使用的优化),只要它可以评估对象的运行时类型,就可以对调用进行去虚拟化。
然而,在 C++0x 中,我们得到了两个新关键字:
override
和final
,两者都可以应用于成员函数(final
也可以应用于一个类)。override
:指定此函数重写基类中的虚函数,当情况并非如此时,可用于获得警告final
:指定此函数(虚函数)不能被在儿童班级中被覆盖。因此,您的类将变为:
注意:使用 final 并不强制编译器对函数调用进行虚拟化(从标准的角度来看),但任何有价值的编译器都应该这样做。
In C++03, no.
As others said, it is a compiler optimization (and a frequently used one) to de-virtualize he call whenever it can assess that the runtime type of the object.
However, in C++0x we get two new keywords:
override
andfinal
and both can be applied to member functions (final
can also be applied to a class).override
: specify that this function overrides a virtual function in a base class, useful to get warned when this is not the casefinal
: specify that this function (virtual) cannot be overriden in children classes.Your class would thus become:
Note: using final does not mandate that the compiler devirtualize function calls (from the Standard point of view), but any compiler worth its salt should do so.
在您的具体示例中,如果
callStatically
被内联,编译器可能会避免虚拟函数分派,因为它可以看到对象的实际类型(因为它是局部变量)。也许您的编译器还可以避免像这样的情况的虚拟调度:
无论
callStatically
是否内联,编译器都可能执行此优化,因为它可以看到变量成员的实际类型。但据我所知,一般没有办法强制编译器绕过虚拟调用。
In your specific example, if
callStatically
gets inlined, the compiler will probably avoid the virtual function dispatch because it can see the object's actual type (because it is a local variable).Probably your compiler can also avoid a virtual dispatch for cases like this:
The compiler is likely to perform this optimization whether or not
callStatically
is inlined, because it can see the actual type of the variable member.But to my knowledge, there is no way to force the compiler to bypass the virtual call in general.
答案就在你的问题中。
当您使用对象调用
virtual
函数时,没有virtual
调度。它使用对象的静态类型调用该函数。仅当您尝试使用指针或引用调用函数时,
虚拟
函数才会出现。编辑:在更新的问题中,您使用
Derived&
调用func()
。通过引用调用将确保发生虚拟调度。因此,没有语言工具(如 Java 中的final
)可以停止virtual
调度。The answer lies in your question.
When you call a
virtual
function using object, there is novirtual
dispatch. It calls the function using the static-type of the object.virtual
function comes into the picture only when you try to call a function using a pointer or a reference.Edit: In your updated question, you are using
Derived&
to callfunc()
. Calling by reference will make sure thatvirtual
dispatch happens. So there is no language facility (likefinal
in Java), which will stopvirtual
dispatch.