gpt4 book ai didi

c++ - 从派生类对象调用基类方法

转载 作者:IT老高 更新时间:2023-10-28 12:34:17 34 4
gpt4 key购买 nike

如何从派生类对象调用被派生类覆盖的基类方法?

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;
}

最佳答案

您始终可以 (*) 使用限定 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 的一些错别字。]

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

Base::foo不是 virtual ,然后 Derived::foo不会覆盖 Base::foo .相反, Derived::foo兽皮 Base::foo .可以在以下示例中看到差异:
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
}

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

一个合格的 id 是形式 X :: Y或只是 :: Y . ::之前的部分指定我们要查找标识符的位置 Y .在第一种形式中,我们查找 X ,然后我们查找 Y从内部 X的上下文。在第二种形式中,我们查找 Y在全局命名空间中。

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

在表达式中 b->foo , 两者 bfoo是不合格的 ID。 b在当前上下文中查找(在上面的示例中是 main 函数)。我们找到了局部变量 Base* b .因为 b->foo有类成员访问的形式,我们查找 foo来自 b 类型的上下文(或者更确切地说 *b )。所以我们查找 foo来自 Base 的上下文.我们会找到成员函数 void foo()内部声明 Base ,我将其称为 Base::foo .

对于 foo ,我们现在完成了,调用 Base::foo .

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

查名字时 foo来自 Derived的上下文,我们会发现 Derived::foo .这就是为什么 Derived::foo据说隐藏 Base::foo .表达式如 d.foo()或者,在 Derived 的成员函数中,只需使用 foo()this->foo() , 将从 Derived 的上下文中查找.

使用限定 ID 时,我们明确说明在何处查找名称的上下文。表达式 Base::foo声明我们要查找名称 foo来自 Base 的上下文(例如,它可以找到 Base 继承的函数)。 此外,它禁用虚拟调度。

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

有趣的事实:纯虚函数可以有一个实现。它们不能通过虚拟分派(dispatch)调用,因为它们需要被覆盖。但是,您仍然可以通过使用限定 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
}

请注意,类成员和基类的访问说明符都会影响您是否可以对 使用限定 ID。调用派生类型对象上的基类函数。

例如:
#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_funprivate_fun,并在限定 id 调用中获得相同的行为和错误)。
p.Base::private_fun() 中的错误与 r.Base::public_fun() 中的错误不同顺便说一句:第一个已经无法引用名称 Base::private_fun (因为它是私有(private)名称)。第二个转换失败 r来自 Private_derived&Base&this -指针(本质上)。这就是为什么第二个在 Private_derived 内起作用的原因或 Private_derived的 friend .

关于c++ - 从派生类对象调用基类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15853031/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com