如何从派生类对象调用被派生类覆盖的基类方法?
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;
}
如何从派生类对象调用被派生类覆盖的基类方法?
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引用基类的函数:
#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在第二种形式中,我们在全局命名空间中查找。
unqualified -id不包含 a ::,因此(本身)不指定查找名称的上下文。
在一个表达式b->foo中,b和foo都是不合格的 ids。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()or 之类的表达式,在 的成员函数中Derived,简单地使用foo()or this->foo(),将从 的上下文中查找Derived。
当使用qualified-id时,我们明确说明了查找名称的上下文。该表达式Base::foo表明我们foo要从上下文中查找名称Base(例如,它可以找到Base继承的函数)。此外,它禁用虚拟调度。
因此,d.Base::foo()会找到Base::foo并调用它;d.Base::bar()会找到Base::bar并调用它。
有趣的事实:纯虚函数可以有一个实现。它们不能通过虚拟调度调用,因为它们需要被覆盖。但是,您仍然可以使用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
}
请注意,类成员和基类的访问说明符都会影响您是否可以使用限定 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_fun并private_fun在限定 ID 调用中获得相同的行为和错误)。
顺便说一下,错误与错误p.Base::private_fun()不同r.Base::public_fun():第一个错误已经无法引用名称Base::private_fun(因为它是私有名称)。第二个无法转换r为Private_derived&-指针(基本上)。这就是为什么第二个来自内部或朋友的工作。Base&thisPrivate_derivedPrivate_derived
首先 Derived 应该从 Base 继承。
class Derived : public Base{
那说
首先,你不能在 Derived 中有 foo
class Base{
public:
void foo(){cout<<"base";}
};
class Derived : public Base{
}
int main(){
Derived bar;
bar.foo() // calls Base::foo()
return 0;
}
其次,您可以让 Derived::foo 调用 Base::foo。
class Base{
public:
void foo(){cout<<"base";}
};
class Derived : public Base{
public:
void foo(){ Base::foo(); }
^^^^^^^^^^
}
int main(){
Derived bar;
bar.foo() // calls Base::foo()
return 0;
}
第三,您可以使用 Base::foo 的合格 id
int main(){
Derived bar;
bar.Base::foo(); // calls Base::foo()
return 0;
}
首先考虑foo()虚拟化。
class Base {
public:
virtual ~Base() = default;
virtual void foo() { … }
};
class Derived : public Base {
public:
virtual void foo() override { … }
};
但是,这可以完成工作:
int main() {
Derived bar;
bar.Base::foo();
return 0;
}
一个重要的 [附加] 注意:如果发生名称隐藏,您仍然会遇到编译错误。
在这种情况下,要么使用 using 关键字,要么使用限定符。此外,请参阅此答案。
#include <iostream>
class Base{
public:
void foo(bool bOne, bool bTwo){std::cout<<"base"<<bOne<<bTwo;}
};
class Derived : public Base
{
public:
void foo(bool bOne){std::cout<<"derived"<<bOne;}
};
int main()
{
Derived bar;
//bar.foo(true,true); // error: derived func attempted
bar.foo(true); // no error: derived func
bar.Base::foo(true,true); // no error: base func, qualified
return 0;
}