基类-> C++ 中的派生类和反之亦然的转换;
我有以下示例代码:
#include <iostream>
#include <string>
using namespace std;
class Event
{
public:
string type;
string source;
};
class KeyEvent : public Event
{
public:
string key;
string modifier;
};
class MouseEvent : public Event
{
public:
string button;
int x;
int y;
};
void handleEvent(KeyEvent e)
{
if(e.key == "ENTER")
cout << "Hello world! The Enter key was pressed ;)" << endl;
}
Event generateEvent()
{
KeyEvent e;
e.type = "KEYBOARD_EVENT";
e.source = "Keyboard0";
e.key = "SPACEBAR";
e.modifier = "none";
return e;
}
int main()
{
KeyEvent e = generateEvent();
return 0;
}
我无法编译它,G++ 抛出一个错误:
main.cpp: In function 'int main()':
main.cpp:47:29: error: conversion from 'Event' to non-scalar type 'KeyEvent' requested
我知道这个错误对于 C++ 大师来说是显而易见的,但我不明白为什么我不能从基类对象进行转换到派生一。有人可以建议我解决我遇到的问题吗?谢谢建议
I have the following example code:
#include <iostream>
#include <string>
using namespace std;
class Event
{
public:
string type;
string source;
};
class KeyEvent : public Event
{
public:
string key;
string modifier;
};
class MouseEvent : public Event
{
public:
string button;
int x;
int y;
};
void handleEvent(KeyEvent e)
{
if(e.key == "ENTER")
cout << "Hello world! The Enter key was pressed ;)" << endl;
}
Event generateEvent()
{
KeyEvent e;
e.type = "KEYBOARD_EVENT";
e.source = "Keyboard0";
e.key = "SPACEBAR";
e.modifier = "none";
return e;
}
int main()
{
KeyEvent e = generateEvent();
return 0;
}
I can't compile it, G++ throws an error of kind:
main.cpp: In function 'int main()':
main.cpp:47:29: error: conversion from 'Event' to non-scalar type 'KeyEvent' requested
I know that the error is obvious for C++ guru's, but I can't understand why I can't do the conversion from base class object to derived one. Can someone suggest me the solution of the problem that I have? Thx in advice
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您的函数
generateEvent
执行以下操作:KeyEvent
然后您尝试获取该
Event
对象复制并再次放入KeyEvent
中。您正在尝试使用多态性,但实际上只是切片。考虑(谨慎!)动态分配:
另请注意,
return 0;
隐含在入口点函数中。Your function
generateEvent
does the following:KeyEvent
You then try to take that
Event
object copy and put it into aKeyEvent
again.You are trying to use polymorphism but are actually just slicing. Consider (with caution!) dynamic allocation:
Also note that
return 0;
is implicit in the entrypoint function.generateEvent
函数通过值(而不是通过指针或引用)传递Event
。这意味着您尝试传递的KeyEvent
对象将被“切片”为Event
对象,并且key
和修饰符
字段将被丢弃。错误消息并不是最有帮助的,但编译器试图说明的是它无法将
Event
值转换为KeyEvent
值。转换需要合成KeyEvent
字段的默认值,因为当按值返回Event
对象时,原始字段被切掉。您可以通过在
generateEvent
中动态分配KeyEvent
并让generateEvent
返回Event*
来避免此错误,或者让generateEvent
通过引用接受KeyEvent
。通过使用指针或引用,可以避免对象切片问题。The
generateEvent
function passes anEvent
by value (rather than by pointer or reference). This means that theKeyEvent
object you are trying to pass will be "sliced" down to anEvent
object, and thekey
andmodifier
fields will be discarded.The error message is not the most helpful, but what the compiler is trying to say is that it can't convert an
Event
value to aKeyEvent
value. The conversion would require synthesizing default values for theKeyEvent
fields, because the original fields were sliced away when theEvent
object was returned by value.You can avoid this error by either dynamically allocating a
KeyEvent
ingenerateEvent
, and havinggenerateEvent
return anEvent*
, or by havinggenerateEvent
accept aKeyEvent
by reference. By using a pointer or reference, you can avoid the object slicing problem.自动从
Event
转换为KeyEvent
是不可能的,编译器不知道要放入什么内容,例如KeyEvent::key
。请小心建议的
cast
解决方案,因为没有类型检查,一旦收到不同类型的事件(Event
是>KeyEvent
还是MouseEvent
?)。常见的解决方案是添加类型 ID 或使用虚拟函数(更安全,但有时不太简单)。It's just impossible to automatically convert from
Event
toKeyEvent
, the compiler doesn't know what to put into e.g.KeyEvent::key
then.Be careful with the proposed
cast
solutions, as there is no type checking, and you will have problems as soon as you receive events of different types (is anEvent
aKeyEvent
or aMouseEvent
?). Common solutions are to add type ids or to use virtual functions (safer, but sometimes way less straightforward).这一行的作用是:
调用
KeyEvent
的构造函数,该构造函数接受Event
对象或对事件对象的引用。但是,您的KeyEvent
类没有这样的构造函数,因此编译器告诉您它无法从Event
中创建KeyEvent
代码>对象(“错误:请求从‘Event’转换为非标量类型‘KeyEvent’”)。您可以使用以下代码:
http://codepad.org/DcBi7jxq
What this line is supposed to do:
is call a constructor of
KeyEvent
that takes either anEvent
object or a reference to one. YourKeyEvent
class, however, does not have such a constructor, so your compiler is telling you that it can't make aKeyEvent
out of anEvent
object ("error: conversion from 'Event' to non-scalar type 'KeyEvent' requested").What you could use instead is this code:
http://codepad.org/DcBi7jxq
您遇到的问题是基于这样一个事实:虽然
generateEvent
实际上创建了一个KeyEvent
,但只有程序员(您)知道这一点。 编译器知道的是generateEvent
返回一个Event
,在一般情况下,它实际上不是代码>KeyEvent。因此,编译器会抱怨您正在将形式上(如函数定义所述)不是KeyEvent
的东西视为KeyEvent
。最有可能的是,如果事件实际上是一个
KeyEvent
,您想要在main
中执行的操作是执行某些操作。这是一种常见的情况,您尝试做的事情没有任何问题。你只需要以不同的方式去做。在本例中,我们要做的是对事件“执行操作 X”,其中“操作 X”根据事件是 KeyEvent 还是其他事件而有所不同。实现此目的的方法是使用虚函数,如下所示:
然后:
对于每个派生类,
PerformActionX
的实现将有所不同。该方法也可以是纯虚拟的或不是纯虚拟的。所有这一切都取决于您到底想做什么。最后一点,有些场景(以及这个问题的一些答案)建议尝试“发现”事件
e
到底是什么类型,然后转换为该类型并执行一些显式操作(例如访问KeyEvent
的key
成员)(如果它是特定类型)。这种处理称为类型切换,这通常是一个坏主意。虽然可能存在需要类型切换的有效场景,但最好以面向对象语言(使用虚拟函数)处理此类情况的方式来处理它们。首先学会如何按规则做事,然后再去打破规则。The problem you have is based on the fact that while
generateEvent
does in fact create aKeyEvent
, this is something that only the programmer (you) knows. What the compiler knows is thatgenerateEvent
returns anEvent
, which in the general case is not in fact aKeyEvent
. Therefore, the compiler complains that you are treating something that formally (as the function definition states) is not aKeyEvent
as aKeyEvent
.Most probably, what you want to do inside
main
is to perform some action if the event is in fact aKeyEvent
. This is a common scenario, and there is nothing wrong with what you are trying to do. You just need to do it differently.In this case, what we want to do is "perform action X" on the event, where "action X" is something different depending on whether the event is a
KeyEvent
or something else. The way to do it is with virtual functions, like so:And then:
The implementation of
PerformActionX
would be different for each derived class. The method could also be pure virtual or not. All this is dependent on what exactly you would want to do.As a final note, there are scenarios (and some answers to this question) which suggest trying to "discover" exactly what type of event
e
is, and then casting to that type and performing some explicit action (like e.g. accessing thekey
member of aKeyEvent
) if it is a specific type. This kind of handling is called a type switch, and it's generally a bad idea. While there might be valid scenarios where a type switch is called for, it is a much better idea to handle such cases the way they are meant to be handled in an object-oriented language (with virtual functions). First learn how to do things by the rules, and leave breaking the rules for later.