C++ 从派生类对象调用基类方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15853031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Call base class method from derived class object
提问by Xun Yang
How can I call a base class method which is overridden by the derived class, from a derived class object?
如何从派生类对象调用被派生类覆盖的基类方法?
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;
}
回答by dyp
You can always(*) refer to a base class's function by using a qualified-id:
您始终可以 (*) 使用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;
}
[Also fixed some typos of the OP.]
[还修正了 OP 的一些错别字。]
(*) Access restrictions still apply, and base classes can be ambiguous.
(*) 访问限制仍然适用,基类可能不明确。
If Base::foo
is not virtual
, then Derived::foo
does not overrideBase::foo
. Rather, Derived::foo
hidesBase::foo
. The difference can be seen in the following example:
如果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
is implicitly virtual even if you don't use the virtual
keyword, as long as it's signature is compatible to Base::bar
.)
(Derived::bar
即使您不使用virtual
关键字,它也是隐式虚拟的,只要它的签名与 兼容Base::bar
。)
A qualified-idis either of the form X :: Y
or just :: Y
. The part before the ::
specifies where we want to look up the identifier Y
. In the first form, we look up X
, then we look up Y
from within X
's context.In the second form, we look up Y
in the global namespace.
一个合格的 id要么是形式X :: Y
要么就是:: Y
。之前的部分::
指定我们要查找标识符的位置Y
。在第一种形式中,我们查找X
,然后Y
从X
的上下文中查找。在第二种形式中,我们Y
在全局命名空间中查找。
An unqualified-iddoes not contain a ::
, and therefore does not (itself) specify a context where to look up the name.
一个不合格的-ID不包含::
,因此不(本身)指定一个范围内去哪里找了名。
In an expression b->foo
, both b
and foo
are unqualified-ids. b
is looked up in the current context (which in the example above is the main
function). We find the local variable Base* b
. Because b->foo
has the form of a class member access, we look up foo
from the context of the type of b
(or rather *b
). So we look up foo
from the context of Base
. We will find the member function void foo()
declared inside Base
, which I'll refer to as Base::foo
.
在表达式中b->foo
,b
和foo
都是unqualified-ids。b
在当前上下文中查找(在上面的示例中是main
函数)。我们找到局部变量Base* b
。因为b->foo
具有类成员访问的形式,我们foo
从上下文的类型b
(或更确切地说*b
)中查找。所以我们foo
从Base
. 我们将找到在void foo()
内部声明的成员函数Base
,我将其称为Base::foo
。
For foo
, we're done now, and call Base::foo
.
对于foo
,我们现在完成了,然后调用Base::foo
。
For b->bar
, we first find Base::bar
, but it is declared virtual
. Because it is virtual
, we perform a virtual dispatch. This will call the final function overrider in the class hierarchy of the type of the object b
points to. Because b
points to an object of type Derived
, the final overrider is Derived::bar
.
对于b->bar
,我们首先查找Base::bar
,但它是声明的virtual
。因为是这样virtual
,我们执行了虚拟调度。这将调用对象b
指向的类型的类层次结构中的最终函数覆盖器。因为b
指向一个类型的对象Derived
,所以最终的覆盖是Derived::bar
.
When looking up the name foo
from Derived
's context, we will find Derived::foo
. This is why Derived::foo
is said to hideBase::foo
. Expressions such as d.foo()
or, inside a member function of Derived
, using simply foo()
or this->foo()
, will look up from the context of Derived
.
foo
从Derived
的上下文中查找名称时,我们会发现Derived::foo
. 这就是为什么Derived::foo
说要躲Base::foo
。诸如d.foo()
or 之类的表达式,在 的成员函数内Derived
,仅使用foo()
or this->foo()
,将从 的上下文中查找Derived
。
When using a qualified-id, we explicitly state the context of where to look up a name. The expression Base::foo
states that we want to look up the name foo
from the context of Base
(it can find functions that Base
inherited, for example). Additionally, it disables virtual dispatch.
使用qualified-id 时,我们明确说明在何处查找名称的上下文。该表达式Base::foo
表明我们foo
要从上下文中Base
查找名称(Base
例如,它可以找到继承的函数)。此外,它禁用虚拟调度。
Therefore, d.Base::foo()
will find Base::foo
and call it; d.Base::bar()
will find Base::bar
and call it.
因此,d.Base::foo()
会找到Base::foo
并调用它;d.Base::bar()
会找到Base::bar
并调用它。
Fun fact: Pure virtual functions can have an implementation. They cannot be called via virtual dispatch, because they needto be overridden. However, you can still call their implementation (if they have one) by using a qualified-id.
有趣的事实:纯虚函数可以有一个实现。它们不能通过虚拟分派调用,因为它们需要被覆盖。但是,您仍然可以使用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
}
Note that access-specifiersboth of class members and base classes have an influence on whether or not you can use a qualified-id to calla base class's function on an object of a derived type.
请注意,类成员和基类的访问说明符都会影响您是否可以使用限定 ID在派生类型的对象上调用基类的函数。
For example:
例如:
#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
}
Accessibility is orthogonal to name lookup. So name hiding does not have an influence on it (you can leave out public_fun
and private_fun
in the derived classes and get the same behaviour and errors for the qualified-id calls).
可访问性与名称查找正交。因此,名称隐藏不会对其产生影响(您可以在派生类中省略public_fun
和private_fun
并获得与合格 ID 调用相同的行为和错误)。
The error in p.Base::private_fun()
is different from the error in r.Base::public_fun()
by the way: The first one already fails to refer to the name Base::private_fun
(because it's a private name). The second one fails to convert r
from Private_derived&
to Base&
for the this
-pointer (essentially). This is why the second one works from within Private_derived
or a friend of Private_derived
.
中的错误p.Base::private_fun()
是从错误中不同r.Base::public_fun()
的方式:第一种已经没有提到名字Base::private_fun
(因为它是一个专用名称)。第二个未能转换r
从Private_derived&
到Base&
了this
终场前(基本)。这就是为什么第二个从内部Private_derived
或Private_derived
.
回答by Xun Yang
First of all Derived should inherit from Base.
首先,Derived 应该继承自 Base。
class Derived : public Base{
That said
那说
First of you can just not have foo in Derived
首先你不能在 Derived 中使用 foo
class Base{
public:
void foo(){cout<<"base";}
};
class Derived : public Base{
}
int main(){
Derived bar;
bar.foo() // calls Base::foo()
return 0;
}
Second you can make Derived::foo call Base::foo.
其次,您可以让 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;
}
Third you can use qualified id of Base::foo
第三,您可以使用 Base::foo 的限定 ID
int main(){
Derived bar;
bar.Base::foo(); // calls Base::foo()
return 0;
}
回答by Xun Yang
Consider making foo()
virtual in the first place.
首先考虑制作foo()
虚拟。
class Base {
public:
virtual ~Base() = default;
virtual void foo() { … }
};
class Derived : public Base {
public:
virtual void foo() override { … }
};
However, this does the job:
但是,这样做可以:
int main() {
Derived bar;
bar.Base::foo();
return 0;
}
回答by bunkerdive
An important [additional] note: you will still have compilation errors if Name Hidingoccurs.
一个重要的 [附加] 说明:如果发生名称隐藏,您仍然会遇到编译错误。
In this case, either utilize the using keyword, or use the qualifer. Additionally, see this answeras well.
在这种情况下,要么使用 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;
}