如何从派生类对象调用被派生类覆盖的基类方法?
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&
this
Private_derived
Private_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;
}