如何将父类转换为子类
Posted
技术标签:
【中文标题】如何将父类转换为子类【英文标题】:How do I cast a parent class as the child class 【发布时间】:2010-11-03 17:19:52 【问题描述】:自从我不得不编写 C++ 代码以来已经有一段时间了,我感觉有点愚蠢。我编写的代码类似于,但不完全是,下面的代码:
class Parent
...
;
class Child : public Parent
...
;
class Factory
static Parent GetThing() Child c; return c;
;
int main()
Parent p = Factory::GetThing();
Child c1 = p; // Fails with "Cannot convert 'Parent' to 'Child'"
Child c2 = (Child)p; // Fails with "Could not find a match for 'TCardReadMessage::TCardReadMessage(TCageMessage)'"
我知道这应该很简单,但我不确定我做错了什么。
【问题讨论】:
我不明白工厂在做什么。看起来它正在返回一个局部变量。该对象有效吗? @John:它正在返回本地对象的副本。回报是按价值计算的,所以原件之后是否死亡并不重要(当然,它确实如此)。没有错,除了它不适合工厂功能...... 是的,Factory 类的 GetThing 方法正在返回一个局部变量。这显然不会做我想要的。我应该改用指针。至少根据下面的答案。 【参考方案1】:由值返回的Parent
对象不能可能包含任何Child
信息。您必须使用指针,最好是智能指针,因此您不必自己清理:
#include <memory>
class Factory
// ...
public:
static std::unique_ptr<Parent> GetThing()
return std::make_unique<Child>();
;
int main()
std::unique_ptr<Parent> p = Factory::GetThing();
if (Child* c = dynamic_cast<Child*>(p.get()))
// do Child specific stuff
【讨论】:
首先,Child *c
在演员表表达式中。你错过了*
。其次,向下转换dynamic_cast
需要多态类型。不知道 OP 的类型是多态的。如果Parent
不是多态的,您的代码将无法编译。
为什么它们不是多态的? Child 使用 public 修饰符从 Parent 继承。
@Andrey:为什么有人会命名两个不相关的类Parent
和Child
? @James:你错过了一个冒号,public static
是 C#,而不是 C++ ;-)
@Mykroft:如果Parent
没有虚函数,那么它们在与dynamic_cast
相关的意义上不是多态的。
@Steve 啊,这是有道理的。这对我的问题并不重要,但我正在编写的实际代码确实具有虚函数。【参考方案2】:
参考下面的代码sn-p:
Child* c = dynamic_cast<Child*>(parentObject);
其中,parentObject
的类型为 Parent*
确保“parentObject”实际上是“Child”类型,否则为未定义行为。
参考More Info
【讨论】:
【参考方案3】:你不能,真的。您的工厂返回了一个Parent
对象,它是从Child
对象c
[*] 构造的。它的 Child 部分已被切掉,因为它已返回到 main
函数。没有办法恢复它。
也许你想使用指针?
[*] 除了Child c();
声明了一个函数,它没有定义一个对象。但这不是你的真实代码,我猜你的真实类有构造函数参数。
【讨论】:
是的,抱歉,这是关于构造函数的正确假设。【参考方案4】:我认为问题不在于您尝试如何进行演员阵容,而在于您首先要演员的原因。该代码毫无意义——即使它在语法上是有效的。在很容易证明您实际上没有苹果的情况下,您正在尝试将“水果”投射到“苹果”中。只有当你有一个指向“水果”的指针并且你有理由认为它也是一个“苹果”时,动态转换和类似的东西才有用。
【讨论】:
此代码只是一个示例,用于展示我的代码如何组合在一起的相关部分。这不是我的实际生产代码。【参考方案5】:您不能将父类的对象强制转换为子类类型。父类的对象是……嗯,父类的对象。子类扩展父类,这意味着父类的对象通常比子类的对象“小”。因此,将父类转换为子类(或重新解释)毫无意义。
解释你想要做什么。没有解释,你的问题根本没有意义。
【讨论】:
【参考方案6】:您可能根本不想在这里投射。如果 Parent 有任何抽象方法,您只需调用它们,派生类将自动正确处理它们。
有时您将相对不相关的项目链接在一起只是为了将它们存储在一个集合中,无论是变体类型还是不同状态导致不相关对象以不同方式处理的情况,在这些情况下您可能想要强制转换。
顺便说一句,我很惊讶您在 GetThing() 上没有收到编译器错误,因为您已将 c 声明为函数,因此您没有返回 Parent。
另外,顺便说一句,如果你按值复制,你会这样“切片”:
Child c;
Parent p(c);
Child & c2 = dynamic_cast< Child& >(p); // throws bad_cast
【讨论】:
【参考方案7】:您可以使用单参数构造函数进行转换: 即(父母工作,孩子学习)如下:
#include <iostream>
using std::cout;
class Parent
public:
void goToWork()
cout<<"working\n"; // only parents work
;
class Child : public Parent
public:
Child(const Parent& parentAddr)
void goToSchool()
cout<<"studying\n"; // only children studies
;
int main(void)
Child child(*(new Parent()));
// here's a child working
child.goToWork();
return 0;
你传递一个子类地址作为父类的构造函数参数,你可以使用一个子类 obj 来做父类的事情
【讨论】:
Child
已经是 Parent
,因为它公开继承自它。无需构造 Parent
并将其传递给 Child
的构造函数(在此代码中什么都不做)。【参考方案8】:
您不能转换实际的对象,但可以转换指向对象的指针。
要转换指针,请使用如下代码:
Child* c = reinterpret_cast<Child*>(p);
【讨论】:
同意 max - reinterpret_cast 可以被视为“最后的演员阵容”:) 我为什么要使用 dynamic_cast 或 reinterpret_cast 而不是只说Child *c = (child*)p;
当然不要使用reinterpret_cast
,这对于某些继承层次结构(基本上涉及多重继承的任何地方)都会给出错误的结果。如果您知道对象确实是Child
(在这种情况下不是,因为按值返回),则可以使用static_cast
,如果您想测试它是否可以使用dynamic_cast
是否作为演员的一部分。
@Myk:因为从 C 语言继承而来的 (type)expression
语法并不能明确为什么你要强制转换。价值转换?有点魔力?向下继承层次结构?这些是非常不同的场景,C++ 提供了不同的语法以使程序员的意图清晰。
-1:要获得正确的结果,您需要使用static_cast
或dynamic_cast
,正如@Steve 在他的评论中所描述的那样。为此使用 reinterpret_cast
是 100% 错误的。以上是关于如何将父类转换为子类的主要内容,如果未能解决你的问题,请参考以下文章