如何从派生类对象中调用派生类重写的基类方法?
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;
}
Run Code Online (Sandbox Code Playgroud)
dyp*_*dyp 58
您可以使用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;
}
Run Code Online (Sandbox Code Playgroud)
[还修正了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
}
Run Code Online (Sandbox Code Playgroud)
(Derived::bar即使您不使用virtual关键字,也是隐式虚拟的,只要它的签名兼容Base::bar.)
一个合格的-ID或者是形式的X :: Y,或只是:: Y.前面的部分::指定了我们要查找标识符的位置Y.在第一种形式中,我们查找X,然后Y 从内部X查找.在第二种形式中,我们查找Y全局命名空间.
一个不合格的-ID不包含::,因此不(本身)指定一个范围内去哪里找了名.
在表达式中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()或在成员函数内Derived,使用简单foo()或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
}
Run Code Online (Sandbox Code Playgroud)
请注意,类成员和基类的访问说明符都会影响您是否可以使用qualified-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
}
Run Code Online (Sandbox Code Playgroud)
可访问性与名称查找正交.因此,名称隐藏对它没有影响(您可以省略public_fun并private_fun在派生类中,并为qualified-id调用获得相同的行为和错误).
中的错误p.Base::private_fun()是从错误中不同r.Base::public_fun()的方式:第一种已经没有提到名字Base::private_fun(因为它是一个专用名称).第二个未能转换r从Private_derived&到Base&了this终场前(基本).这就是为什么第二个在内部Private_derived或朋友的作用Private_derived.
小智 12
首先,Derived应该继承自Base.
class Derived : public Base{
Run Code Online (Sandbox Code Playgroud)
那就是说
首先你可以在Derived中没有foo
class Base{
public:
void foo(){cout<<"base";}
};
class Derived : public Base{
}
int main(){
Derived bar;
bar.foo() // calls Base::foo()
return 0;
}
Run Code Online (Sandbox Code Playgroud)
其次,你可以使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;
}
Run Code Online (Sandbox Code Playgroud)
第三,你可以使用Base :: foo的限定id
int main(){
Derived bar;
bar.Base::foo(); // calls Base::foo()
return 0;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
65920 次 |
| 最近记录: |