如何从派生类对象中调用派生类重写的基类方法?
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;
}
答案 0 :(得分:56)
您可以使用 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
兼容。)
qualified-id 的格式为X :: Y
或:: Y
。 ::
之前的部分指定了我们要查找标识符Y
的位置。在第一种形式中,我们会查找X
,然后从Y
的上下文中查找X
。在第二种形式中,我们查找{ {1}}在全局命名空间中。
unqualified-id 不包含Y
,因此(本身)不会指定查找名称的上下文。
在表达式::
中,b->foo
和b
都是 unqualified-ids 。在当前上下文中查找foo
(在上面的示例中是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()
的上下文中查找。
使用 qualified-id 时,我们会明确说明查找名称的位置的上下文。表达式Derived
表明我们希望从Base::foo
的上下文中查找名称foo
(例如,它可以找到Base
继承的函数)。 此外,它会禁用虚拟调度。
因此,Base
会找到d.Base::foo()
并将其调用; Base::foo
会找到d.Base::bar()
并将其调用。
有趣的事实:纯虚函数可以有一个实现。它们不能通过虚拟调度来调用,因为它们需要被覆盖。但是,您仍然可以使用 qualified-id 调用其实现(如果有的话)。
Base::bar
请注意, access-specifiers 类成员和基类都会影响您是否可以使用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
}
辅助功能与名称查找正交。因此,名称隐藏不会对其产生影响(您可以在派生类中省略#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
,并为qualified-id调用获取相同的行为和错误。)
private_fun
中的错误与p.Base::private_fun()
中的错误有所不同:第一个错误已经无法引用名称r.Base::public_fun()
(因为它是私有名称)。第二个无法将Base::private_fun
从r
转换为Private_derived&
以获取Base&
- 指针(基本上)。这就是为什么第二个适用于this
或Private_derived
的朋友。
答案 1 :(得分:10)
首先,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;
}
答案 2 :(得分:3)
首先考虑将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;
}
答案 3 :(得分:0)
重要的[附加]注释:如果 名称隐藏 ,则仍会出现编译错误。
在这种情况下,要么使用using关键字,要么使用qualifer。另外,请参阅this answer。
System.Text.RegularExpressions.Regex.Replace("This is a stack of pages on stack overflow. Sometimes also referred to as stack.overflow.com"
,"stack(?!\.overflow)"
,"STACK")