C++ 对于重载函数,调用父实例和子实例的专用版本
我之前问过一个问题,但结果证明我的问题并没有按照我的示例正确建模。这就是我的实际问题:C++ 对于重载函数,调用父实例和子实例的专用版本,c++,inheritance,polymorphism,overloading,C++,Inheritance,Polymorphism,Overloading,我之前问过一个问题,但结果证明我的问题并没有按照我的示例正确建模。这就是我的实际问题: 我有类A,类B继承自A 我有两个函数foo(A&)和foo(B&) 我有一个a*指针列表,其中包含a和B的实例 对于A的实例,如何调用foo(A&);对于B的实例,如何调用foo(B&)?约束条件:我可以修改A和B实现,但不能修改foo的实现 请参见下面的示例: #include <iostream> #include <list> class A { public: }; cla
A
,类B
继承自A
foo(A&)
和foo(B&)
a*
指针列表,其中包含a
和B
的实例A
的实例,如何调用foo(A&)
;对于B
的实例,如何调用foo(B&)
?约束条件:我可以修改A
和B
实现,但不能修改foo
的实现#include <iostream>
#include <list>
class A {
public:
};
class B : public A {
public:
};
void bar(A &a) { std::cout << "This is an A" << std::endl; }
void bar(B &b) { std::cout << "This is a B" << std::endl; }
int main(int argc, char **argv) {
std::list<A *> l;
l.push_back(new B());
l.push_back(new B());
for (std::list<A *>::iterator it = l.begin(); it != l.end(); ++it)
bar(**it);
}
我期待着
This is a B
将指针传递到条
(通过重写其签名)没有帮助
感谢Antonio帮助澄清问题。您正在寻找运行时多态性。虚拟成员方法“自然”支持这一点 另一种方法是使用RTTI和
A*
到B*
并在成功后调用bar
。。。或者static\u cast
如果您确实确定存在B*
对象。通常需要向下转换表示设计有问题
重要注意事项:运行时签入要求类型无论如何都是多态的。也许您特定的A
可以实现这一点,但您无法更改类。否则,static\u cast
是唯一可用的选项
如果您可以控制类,则可以使用标准多态性和重载机制,使用this
上的虚拟方法作为“外部”调用的门面:
#包括
#包括
甲级;
无效外螺纹(A&);
甲级{
公众:
虚拟空栏(){external_栏(*this);};
};
乙级;;
空心外螺纹杆(B&)//重要的
B类:公共A{
公众:
虚拟空栏(){external_栏(*this);};
};
void external_-bar(A&A){std::cout编辑:这回答了问题的第一个版本,现在改为查看
如果您这样做:
A* b = B();
然后,*b
将是A型。这就是你在for周期中所做的。这不涉及“虚拟性”或政治主义
以下代码给出了您要查找的行为:
class A {
public:
virtual void bar() { std::cout << "This is an A" << std::endl; }
};
class B : public A {
public:
virtual void bar() { std::cout << "This is a B" << std::endl; }
};
int main(int argc, char **argv) {
std::list<A *> l;
l.push_back(new B());
l.push_back(new B());
l.push_back(new A());
l.push_back(new B());
for (std::list<A *>::iterator it = l.begin(); it != l.end(); ++it)
(*it)->bar();
}
将打印这是一个b
其他人已经解释了如何实现它
我只想解释一下为什么会这样
B在这里隐式转换为A。因此,它当前只有A的属性
上向铸造在C++中是隐含的。
<> Downcasting在C++中只有当基类是多态的时候才是可能的。
简言之,多态性需求只不过是基类中可以被派生方法覆盖的东西!!虚拟方法
然后,您可以按照其他人的规定使用RTTI和dynamic_cast来实现这一点
例如:
#包括
#包括
甲级{
公众:
虚空虚拟对象()=0;
};
B类:公共A{
公众:
void dummy(){}
};
void bar(A&A){std::coutAntonio编写了一个涉及虚拟函数的好解决方案。如果出于某种原因您确实不想使用虚拟函数,那么您可以在自由函数中使用dynamic_cast
:
#include <iostream>
#include <list>
struct A {
virtual ~A() {} // important
};
struct B : A {};
void bar(A &a) { std::cout << "This is an A" << std::endl; }
void bar(B &b) { std::cout << "This is a B" << std::endl; }
void bar_helper(A *ptr)
{
if ( auto b = dynamic_cast<B *>(ptr) )
bar(*b);
else
bar(*ptr);
}
int main()
{
std::list<A *> ls;
ls.push_back(new B);
ls.push_back(new B);
ls.push_back(new A);
for (auto ptr : ls)
{
bar_helper(ptr);
delete ptr;
}
ls.clear();
}
#包括
#包括
结构A{
虚拟~A(){}//重要
};
结构B:A{};
void bar(A&A){std::cout由于重载是在编译时解决的,因此您需要向编译器提供足够的信息,以决定要调用的bar
的正确重载。由于您希望根据对象的运行时类型动态地做出决定,虚拟函数将非常有帮助:
struct A {
virtual void bar() { bar(*this); }
};
struct B : public A {
virtual void bar() { bar(*this); }
};
看起来主体是相同的,因此可以消除B::bar
,但事实并非如此:虽然主体看起来完全相同,但由于C++中重载的静态解析,它们调用不同的bar
s:
- 在
A::bar
中,*此
的类型是A&
,因此调用第一个重载
- 在
B::bar
中,*此
的类型为B&
,因此调用第二个重载
修改调用代码以调用成员bar
将完成更改:
std::list<A *> l;
l.push_back(new B());
l.push_back(new B());
for (std::list<A *>::iterator it = l.begin(); it != l.end(); ++it)
(*it)->bar();
std::list l;
l、 向后推(新B());
l、 向后推(新B());
对于(std::list::iterator it=l.begin();it!=l.end();++it)
(*it)->bar();
如果**它的类型是A
,那么您为什么期望“这是一个B”?使用虚拟方法A::bar()
和B::bar()
您将看到您期望的结果。因为我在其中分配了一个B。这无关紧要。重载解析如何知道指向a
的指针实际上指向aB
?重载解析发生在编译时。@LukeSkywalker:如果您想让重载在基类指针上正常工作,您必须使用虚拟机member functions.OP要求为非成员函数提供解决方案,这似乎不是XY问题。@luk32我相信我的答案在这里解决了这个问题。让我们看看OP的反应。Antonio,如果bar仍然是类之外的函数,并且由a和B的虚拟成员方法调用,我会接受这个答案(例如称为foo)它本身会调用bar。@如果允许我们更改类签名,当然可以。这是正确的方法。请注意,可以委托给一个自由函数;例如,自由的bar()
可以保持OP的状态,而虚拟函数将是虚拟的void bar\u helper(){bar(*this);}
,您需要在每个类中编写它(您可以通过CRTP派生,使其看起来更整洁),老实说,这是OP将要走的路线。总是有更丑陋的解决方案使用类型安全的联合,如boost::variant
另一个选项是由AndyG间接提供的。使用Virtual
#include <iostream>
#include <list>
struct A {
virtual ~A() {} // important
};
struct B : A {};
void bar(A &a) { std::cout << "This is an A" << std::endl; }
void bar(B &b) { std::cout << "This is a B" << std::endl; }
void bar_helper(A *ptr)
{
if ( auto b = dynamic_cast<B *>(ptr) )
bar(*b);
else
bar(*ptr);
}
int main()
{
std::list<A *> ls;
ls.push_back(new B);
ls.push_back(new B);
ls.push_back(new A);
for (auto ptr : ls)
{
bar_helper(ptr);
delete ptr;
}
ls.clear();
}
struct A {
virtual void bar() { bar(*this); }
};
struct B : public A {
virtual void bar() { bar(*this); }
};
std::list<A *> l;
l.push_back(new B());
l.push_back(new B());
for (std::list<A *>::iterator it = l.begin(); it != l.end(); ++it)
(*it)->bar();