派生类调用父类的方法,该方法调用重写的虚拟方法将调用错误的方法

时间:2018-09-28 15:00:45

标签: c++ override signature virtual-functions default-parameters

首先,很抱歉标题令人迷惑。我不知道该如何正确表达。

问题不是真正的问题,而是我不知道如何实现的问题。

代码如下:

#include <iostream>

class Parent
{
public:
    virtual void foo()
    {
        std::cout << "Parent's foo" << std::endl;
    }
    void bar()
    {
        foo();
    }
};

class Child : public Parent
{
public:
    void foo()
    {
        std::cout << "Child's foo" << std::endl;
    }
};

int main()
{
    Child c;

    c.bar();

    return 0;
}

上面的代码运行时,它会打印出来Child's foo

但是,相同的代码是,子类foo定义为void foo(bool def = true)的BUT会打印出Parent's foo

如果定义不匹配,是否仍然可以调用子版本的foo而不是父版本的foo?

2 个答案:

答案 0 :(得分:1)

不幸的是,如果您想添加额外的参数(甚至是默认参数),则可以显式创建一个重载函数,该函数在大多数情况下的行为与调用方相似。

#include <iostream>
class Parent
{
public:
    virtual void foo()
    {
        std::cout << "Parent's foo" << std::endl;
    }
    void bar()
    {
        foo();
    }
};

class Child : public Parent
{
public:
    virtual void foo(bool def) // virtual if another subclass needs to override
    {
        std::cout << "Child's foo def = " << def << std::endl;
    }
    virtual void foo()override //override and virtual optional here
    {
        foo(true);
    }
};

int main()
{
    Child c;

    c.bar();
    c.foo();
    c.foo(true);

    return 0;
}

答案 1 :(得分:0)

这纯粹是在C ++中重写函数时的函数。

在C ++中,函数重写是根据成员函数的“签名”完成的:

  • 不合格的名字
  • 声明中的精确参数列表(不包括隐式this
  • 隐式参数this的限定条件

很明显,根据定义,this参数的类型 不能完全匹配,因为根据定义,该类型必须是指向派生类的指针。

[关于参数的简历限定的注意事项:

调用方看到的声明中的参数必须完全相同,即在删除对象副本上无意义的cv限定符之后:这些是函数体内局部变量的cv限定符,而这仅在函数定义中有意义。

void f(const int i); // takes an int by value; const is meaningless
void f(int i); // redeclaration of the same function

// redeclaration of the same function yet again
void f(const int ci) { // const is meaningful here
  ci = 1; // error
}

-尾注]

  

但是相同的代码,但是带有子类foo的定义   void foo(bool def = true)会打印出父母的foo。

因为参数列表不匹配:空参数列表仅与空参数列表匹配

您需要在此处用两个重载函数替换默认参数,而不能转发给另一个:

void foo(bool def); // new function signature 

void foo() { // overrides Parent's member
  foo(true);
}

参数列表很长,很容易更改类型并创建新的函数签名,而不是覆盖基类虚函数;也很容易弄错大写字母或拼写错误(请考虑英语与美国拼写)。通常,错误的函数名称(或任何其他名称:类型,模板,变量...)会导致编译错误,因为未声明具有较小拼写更改的名称。但是,如果使用成员的原始声明以覆盖基类声明为目的,则没有暗示您尝试这样做,并且编译器不会警告您(它可能会警告隐藏基类声明,但这是不同的)。明确标记要使用virtual关键字覆盖的声明没有帮助,引入新的虚函数并不是目的。

这是C ++标准的第一个版本正式化之后的悲惨状况。现在不一样了。

如果要确保确实覆盖了基类声明,则可以使用override关键字:

class Child : public Parent
{
public:
    void foo(bool def);
    void foo() override {
      foo(true);
    }
};