从派生类对象调用基类方法 [英] Call base class method from derived class object

查看:177
本文介绍了从派生类对象调用基类方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从派生类对象调用派生类重写的基类方法?

How can I call a base class method which is overridden by the derived class, from a derived class object?

class Base{
  public:
    void foo(){cout<<"base";}
};

class Derived:public Base{
  public:
    void foo(){cout<<"derived";}
}

int main(){
  Derived bar;
  //call Base::foo() from bar here?
  return 0;
}


推荐答案

你可以随时(*)通过使用 qualified-id 来引用基类的功能:

You can always(*) refer to a base class's function by using a qualified-id:

#include <iostream>

class Base{
  public:
    void foo(){std::cout<<"base";}
};

class Derived : public Base
{
  public:
    void foo(){std::cout<<"derived";}
};

int main()
{
  Derived bar;
  //call Base::foo() from bar here?
  bar.Base::foo(); // using a qualified-id
  return 0;
}

[还修正了OP的一些拼写错误。]

[Also fixed some typos of the OP.]

(*)访问限制仍然适用,基类可能不明确。

(*) Access restrictions still apply, and base classes can be ambiguous.

如果 Base :: foo 不是 virtual ,那么 Derived :: foo 覆盖 Base :: foo 。相反, Derived :: foo 隐藏 Base :: foo 。可以在以下示例中看到差异:

If Base::foo is not virtual, then Derived::foo does not override Base::foo. Rather, Derived::foo hides Base::foo. The difference can be seen in the following example:

struct Base {
   void foo()         { std::cout << "Base::foo\n"; }
   virtual void bar() { std::cout << "Base::bar\n"; }
};

struct Derived : Base {
   void foo()         { std::cout << "Derived::foo\n"; }
   virtual void bar() { std::cout << "Derived::bar\n"; }
};

int main() {
    Derived d;
    Base* b = &d;
    b->foo(); // calls Base::foo
    b->bar(); // calls Derived::bar
}

派生: :bar 即使您不使用 virtual 关键字也是隐式虚拟的,只要它的签名与兼容即可Base :: bar 。)

(Derived::bar is implicitly virtual even if you don't use the virtual keyword, as long as it's signature is compatible to Base::bar.)

qualified-id 的格式为 X :: Y 或只是 :: Y :: 之前的部分指定了我们要查找标识符 Y 的位置。在第一种形式中,我们查找 X ,然后我们从<$ c $中查找 Y c> X 的上下文。在第二种形式中,我们在全局命名空间中查找 Y

A qualified-id is either of the form X :: Y or just :: Y. The part before the :: specifies where we want to look up the identifier Y. In the first form, we look up X, then we look up Y from within X's context. In the second form, we look up Y in the global namespace.

unqualified-id 不包含 :: ,因此(本身)不指定上下文查找名称。

An unqualified-id does not contain a ::, and therefore does not (itself) specify a context where to look up the name.

在表达式 b-> foo 中,两者都 b foo unqualified-ids 。在当前上下文中查找 b (在上面的示例中是 main 函数)。我们找到局部变量 Base * b 。因为 b-> foo 具有类成员访问权限的形式,我们从上下文中查找 foo 类型 b (或者更确切地说 * b )。所以我们从 Base 的上下文中查找 foo 。我们将在 Base 中声明成员函数 void foo(),我将其称为 Base :: foo

In an expression b->foo, both b and foo are unqualified-ids. b is looked up in the current context (which in the example above is the main function). We find the local variable Base* b. Because b->foo has the form of a class member access, we look up foo from the context of the type of b (or rather *b). So we look up foo from the context of Base. We will find the member function void foo() declared inside Base, which I'll refer to as Base::foo.

对于 foo ,我们已经完成了现在,并调用 Base :: foo

For foo, we're done now, and call Base::foo.

对于 b-> bar ,我们首先找到 Base :: bar ,但它被声明为 virtual 。因为它是虚拟,所以我们执行虚拟调度。这将调用对象类型的类层次结构中的最终函数覆盖器 b 指向。因为 b 指向类型为 Derived 的对象,所以最终的覆盖为 Derived :: bar

For b->bar, we first find Base::bar, but it is declared virtual. Because it is virtual, we perform a virtual dispatch. This will call the final function overrider in the class hierarchy of the type of the object b points to. Because b points to an object of type Derived, the final overrider is Derived::bar.

Derived中查找名称 foo 的上下文,我们会找到 Derived :: foo 。这就是为什么 Derived :: foo 被称为隐藏 Base :: foo 。表达式,例如 d.foo(),或者在 Derived 的成员函数中,只使用 foo() this-> foo(),将从派生

When looking up the name foo from Derived's context, we will find Derived::foo. This is why Derived::foo is said to hide Base::foo. Expressions such as d.foo() or, inside a member function of Derived, using simply foo() or this->foo(), will look up from the context of Derived.

使用 qualified-id 时,我们明确说明了查找名称的位置的上下文。表达式 Base :: foo 表示我们要从<$ c $的上下文中查找名称 foo c> Base (例如,它可以找到继承 Base 的函数)。 此外,它会禁用虚拟调度。

When using a qualified-id, we explicitly state the context of where to look up a name. The expression Base::foo states that we want to look up the name foo from the context of Base (it can find functions that Base inherited, for example). Additionally, it disables virtual dispatch.

因此, d.Base :: foo()将找到 Base :: foo 并调用它; d.Base :: bar()将找到 Base :: bar 并调用它。

Therefore, d.Base::foo() will find Base::foo and call it; d.Base::bar() will find Base::bar and call it.

有趣的事实:纯虚函数可以有一个实现。它们不能通过虚拟调度来调用,因为它们需要被覆盖。但是,您仍然可以使用 qualified-id 调用他们的实现(如果他们有)。

Fun fact: Pure virtual functions can have an implementation. They cannot be called via virtual dispatch, because they need to be overridden. However, you can still call their implementation (if they have one) by using a qualified-id.

#include <iostream>

struct Base {
    virtual void foo() = 0;
};

void Base::foo() { std::cout << "look ma, I'm pure virtual!\n"; }

struct Derived : Base {
    virtual void foo() { std::cout << "Derived::foo\n"; }
};

int main() {
    Derived d;
    d.foo();       // calls Derived::foo
    d.Base::foo(); // calls Base::foo
}






<请注意, access-specifiers 类成员和基类都会影响您是否可以使用qualified-id来调用基类的函数派生类型的对象。


Note that access-specifiers both of class members and base classes have an influence on whether or not you can use a qualified-id to call a base class's function on an object of a derived type.

例如:

#include <iostream>

struct Base {
public:
    void public_fun() { std::cout << "Base::public_fun\n"; }
private:
    void private_fun() { std::cout << "Base::private_fun\n"; }
};

struct Public_derived : public Base {
public:
    void public_fun() { std::cout << "Public_derived::public_fun\n"; }
    void private_fun() { std::cout << "Public_derived::private_fun\n"; }
};

struct Private_derived : private Base {
public:
    void public_fun() { std::cout << "Private_derived::public_fun\n"; }
    void private_fun() { std::cout << "Private_derived::private_fun\n"; }
};

int main() {
    Public_derived p;
    p.public_fun();        // allowed, calls Public_derived::public_fun
    p.private_fun();       // allowed, calls Public_derived::public_fun
    p.Base::public_fun();  // allowed, calls Base::public_fun
    p.Base::private_fun(); // NOT allowed, tries to name Base::public_fun

    Private_derived r;
    r.Base::public_fun();  // NOT allowed, tries to call Base::public_fun
    r.Base::private_fun(); // NOT allowed, tries to name Base::private_fun
}

辅助功能是正交的名称查找。因此名称隐藏对它没有影响(您可以在派生类中省略 public_fun private_fun 并获取与qualified-id调用相同的行为和错误。)

Accessibility is orthogonal to name lookup. So name hiding does not have an influence on it (you can leave out public_fun and private_fun in the derived classes and get the same behaviour and errors for the qualified-id calls).

中的错误p.Base :: private_fun() r.Base :: public_fun()中的错误不同:第一个已经无法引用名称 Base :: private_fun (因为它是私人名称)。第二个未能将 r Private_derived& 转换为 Base& 对于这个 -pointer(本质上)。这就是为什么第二个在 Private_derived Private_derived 的朋友中工作。

The error in p.Base::private_fun() is different from the error in r.Base::public_fun() by the way: The first one already fails to refer to the name Base::private_fun (because it's a private name). The second one fails to convert r from Private_derived& to Base& for the this-pointer (essentially). This is why the second one works from within Private_derived or a friend of Private_derived.

这篇关于从派生类对象调用基类方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆