C++ 向下转换结构
C++ Downcasting a struct
我有以下代码:
struct Operation {
public :
OperationName name;
};
struct FilterOperation : Operation {
FilterName filter;
std::list<std::string> params;
};
OperationName 和 FilterName 是枚举,列出了每个操作和过滤器的所有不同名称。
在遍历所有操作的每个循环中,我想将操作向下转换为 FilterOperation:
std::list<Operation> operations
for (Operation op : operations) {
switch (op.name) {
case o_filter :
std::cout << dynamic_cast<FilterOperation*>(&op)->filter << std::endl;
}
}
显然 dynamic_cast 在这里不起作用:
parser.cpp:154:90: error: cannot dynamic_cast ‘& op’ (of type ‘struct Operation*’) to type ‘struct FilterOperation*’ (source type is not polymorphic)
"Op: Filter, Name: " << filterStrings[dynamic_cast<FilterOperation*>(&op)->filter]
我实际上尝试向它添加一个虚函数,但这并没有解决我的实际问题(我不知道如何在这里正确地向下转换)
这是未定义的行为。
op
是一个 Operation
。不是指向 Operation
的指针或引用,而是指向 FilterOperation
的指针或引用。所以 &op
显然不是 FilterOperation*
.
从 cppreference.com 到 dynamic_cast:
dynamic_cast < new_type > ( expression )
If the cast is successful, dynamic_cast returns a value of type new_type. If the cast fails and new_type is a pointer type, it returns a null pointer of that type.
很明显,dynamic_cast<FilterOperation*>(&op)
是一个空指针,解引用它是 UB。
您关于添加虚函数的直觉应该已经为您解决了编译器错误。您确定没有遇到其他错误吗?
无论如何,因为您处理的是对象实例而不是指针,所以这永远行不通。您的列表包含 Operation 对象, 而不是 FilterOperation 对象。如果你想插入 FilterOperation 对象,那么你需要一个指针列表(或者最好是 shared_ptr)而不是按值存储:
std::list<Operation*> operations
for (Operation* op : operations) {
switch (op->name) {
case o_filter :
std::cout << dynamic_cast<FilterOperation*>(op)->filter << std::endl;
}
}
此外,我怀疑您误解了 switch() 对字符串的作用。它可能不会执行您想要的操作,您需要一个 if 语句。
使用 stl 容器,您可以使用 Operation
的复制构造函数和 operator =
。
这些方法仅复制 FilterOperation
中的 Operation
而不是整个结构。
要解决这个问题,您应该使用 std::list<Operation*>
甚至更好,std::list<std::shared_ptr<Operation>>
而不是 std::list<Operation>
这样您就不会将操作复制到列表中,而只是指针...
此外,你必须给Operation
结构添加一个虚拟析构函数,否则你会发生内存泄漏,因为派生的列表class (FilterOperation
) 在您删除 Operation
.
时不会被释放
我有以下代码:
struct Operation {
public :
OperationName name;
};
struct FilterOperation : Operation {
FilterName filter;
std::list<std::string> params;
};
OperationName 和 FilterName 是枚举,列出了每个操作和过滤器的所有不同名称。
在遍历所有操作的每个循环中,我想将操作向下转换为 FilterOperation:
std::list<Operation> operations
for (Operation op : operations) {
switch (op.name) {
case o_filter :
std::cout << dynamic_cast<FilterOperation*>(&op)->filter << std::endl;
}
}
显然 dynamic_cast 在这里不起作用:
parser.cpp:154:90: error: cannot dynamic_cast ‘& op’ (of type ‘struct Operation*’) to type ‘struct FilterOperation*’ (source type is not polymorphic)
"Op: Filter, Name: " << filterStrings[dynamic_cast<FilterOperation*>(&op)->filter]
我实际上尝试向它添加一个虚函数,但这并没有解决我的实际问题(我不知道如何在这里正确地向下转换)
这是未定义的行为。
op
是一个 Operation
。不是指向 Operation
的指针或引用,而是指向 FilterOperation
的指针或引用。所以 &op
显然不是 FilterOperation*
.
从 cppreference.com 到 dynamic_cast:
dynamic_cast < new_type > ( expression )
If the cast is successful, dynamic_cast returns a value of type new_type. If the cast fails and new_type is a pointer type, it returns a null pointer of that type.
很明显,dynamic_cast<FilterOperation*>(&op)
是一个空指针,解引用它是 UB。
您关于添加虚函数的直觉应该已经为您解决了编译器错误。您确定没有遇到其他错误吗?
无论如何,因为您处理的是对象实例而不是指针,所以这永远行不通。您的列表包含 Operation 对象, 而不是 FilterOperation 对象。如果你想插入 FilterOperation 对象,那么你需要一个指针列表(或者最好是 shared_ptr)而不是按值存储:
std::list<Operation*> operations
for (Operation* op : operations) {
switch (op->name) {
case o_filter :
std::cout << dynamic_cast<FilterOperation*>(op)->filter << std::endl;
}
}
此外,我怀疑您误解了 switch() 对字符串的作用。它可能不会执行您想要的操作,您需要一个 if 语句。
使用 stl 容器,您可以使用 Operation
的复制构造函数和 operator =
。
这些方法仅复制 FilterOperation
中的 Operation
而不是整个结构。
要解决这个问题,您应该使用 std::list<Operation*>
甚至更好,std::list<std::shared_ptr<Operation>>
而不是 std::list<Operation>
这样您就不会将操作复制到列表中,而只是指针...
此外,你必须给Operation
结构添加一个虚拟析构函数,否则你会发生内存泄漏,因为派生的列表class (FilterOperation
) 在您删除 Operation
.