我有一个包含一些函数的类(没有虚函数),还有两个类公开继承该类。在这两个子类中,我重写了基类的相同功能。
在main(位于同一个文件)中创建所有三个类的对象之后,我使用baseclass对象调用原始函数,并使用derivedclass对象调用覆盖的函数。
我期待所有3个函数调用从基类运行原始函数(因为我没有在代码中的任何地方使用'虚拟')但我实际上得到了每个函数的每个版本函数根据其定义的类别工作(3个不同的版本)。
我有类Base&得出如下:
struct Base
{
void foo();
};
struct Derived : Base
{
void foo();
};
在main中:
int main()
{
Derived d;
d.foo();
}
如果不使用'虚拟'我认为d.foo()应该运行Base :: foo()。
答案 0 :(得分:7)
这不“覆盖”......并且不需要。
struct Base
{
void foo();
};
struct Derived : Base
{
void foo();
};
int main()
{
Derived d;
d.foo();
}
如果我理解正确,那么你期望执行Base::foo()
,因为这些功能不是虚拟的,因此不会覆盖另一个。
但是,在这里,你不需要虚拟调度:继承规则只是声明你将为你运行它的对象的类型获得正确的函数。
当您需要虚拟调度/覆盖时,情况略有不同:当您使用间接时:
int main()
{
Base* ptr = new Derived();
ptr->foo();
delete ptr;
}
在上面的代码段中,结果将是Base::foo()
被调用,因为表达式ptr->foo()
不知道*ptr
真的 a { {1}}。它只知道Derived
是ptr
。
这是添加Base*
的地方(在这样做的情况下,使一个函数覆盖另一个)会让魔法发生。
答案 1 :(得分:0)
您无法覆盖非虚拟内容。非虚拟成员函数将根据实例对象的类型静态调度。
答案 2 :(得分:0)
你可以通过使一个函数间接调用一个内联函数来“覆盖”一个函数来作弊。像(C++03)
这样的东西 class Foo;
typedef int foo_sig_t (Foo&, std::string&);
class Foo {
foo_sig_t *funptr;
public:
int do_fun(std::string&s) { return funptr(*this,s); }
Foo (foo_sig_t* fun): funptr(fun) {};
~Foo () { funptr= NULL; };
// etc
};
class Bar : public Foo {
static int barfun(Bar&, std::string& s) {
std::cout << s << std::endl;
return (int) s.size();
};
public:
Bar () : Foo(reinterpret_cast<foo_sig_t*>)(&barfun)) {};
// etc...
};
以后:
Bar b;
int x=b.do_fun("hello");
官方说这不会重载虚函数,但看起来非常接近虚拟函数。但是,在我上面的Foo
示例中,每个Foo
实例都有自己的funptr
,它不一定由类共享。但是所有Bar
个实例共享指向同一funptr
的相同 barfun
。
BTW,使用C++11 lambda anonymous functions(内部实现为closures),这将更简单,更短。
当然,virtual functions通常实际上是通过类似的机制实现的:对象(带有一些virtual
个东西)隐含地以隐藏字段开头(可能是“命名为”_vptr
)给出vtable(或虚方法表)。