我有一个非常庞大且成熟的 C++ 代码库,我正在尝试使用 SWIG 为其生成 C# 接口。我无法更改实际的 C++ 代码本身,但我们可以使用 SWIG 提供的任何内容来扩展/更新它。我面临一个问题,如下所示编写的 C++ 函数会导致 C# 出现问题。
A* SomeClass::next(A*)
Run Code Online (Sandbox Code Playgroud)
调用者可能会执行以下操作:
A* acurr = 0;
while( (acurr = sc->next(acurr)) != 0 ){
if( acurr isoftype B ){
B* b = (B*)a;
...do some stuff with b..
}
elseif( acurr isoftype C )
...
}
Run Code Online (Sandbox Code Playgroud)
本质上,迭代元素容器,根据元素的真实类型,执行不同的操作。遗憾的是,SWIG 为“next”函数生成的 C# 层执行了以下操作:
return new A();
Run Code Online (Sandbox Code Playgroud)
因此,C# 中的调用代码无法确定返回的对象是否实际上是派生类,它实际上似乎始终是基类(这确实有道理)。我遇到过几种解决方案:
公共静态对象castTo(对象fromObj,类型toType)
{
对象 retval = … 我有一个正在尝试遍历的错误链接列表。给定MyError,它是带有可选代码的错误链接列表,我的目标是遍历该链并返回第一个非None代码:
type BoxedError = Box<dyn std::error::Error + Send + Sync + 'static>;
#[derive(Debug)]
struct MyError {
code: Option<u32>,
source: Option<BoxedError>,
}
impl std::error::Error for MyError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source().map(|s| s as _)
}
}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt("", f)
}
}
impl MyError {
fn source(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
self.source.as_ref().map(|c| c.as_ref())
}
fn …Run Code Online (Sandbox Code Playgroud) 以下问题的答案描述的推荐用法static_cast,dynamic_cast以及reinterpret_cast在C++:
什么时候应该使用static_cast,dynamic_cast,const_cast和reinterpret_cast?
你知道有哪些工具可以用来检测这类演员的滥用吗?像PC-Lint或Coverity Static Analysis这样的静态分析工具会这样做吗?
提示这个问题的特殊情况是不适当地使用static_cast向下转换指针,编译器没有警告.我想用工具检测这种情况,而不是假设开发人员永远不会犯这个错误.
如果我做
double d = 34.56;
int i = (int)d;
Run Code Online (Sandbox Code Playgroud)
我不是"沮丧"吗?
要么
这个术语只用于类和对象吗?
我很困惑,因为在这种情况下,我们从一个更大的double到另一个更小的"向下倾斜" int,但是在课堂上,我们从一个较小的base class到另一个更"低调" derived class.
在某种意义上,这两种惯例是否相反?
我有一个项目,我在EF中定义了Employer一个派生类User.在我的过程中,我创建了一个用户而不知道它最终是否会成为雇主(或其他类型的用户),之后我需要转换它.起初我尝试过(Intellisense表示存在显式转换):
Employer e = (Employer) GetUser();
Run Code Online (Sandbox Code Playgroud)
但在运行时我得到了:
Unable to cast object of type 'System.Data.Entity.DynamicProxies.User_7B...0D' to type 'Employer'.
Run Code Online (Sandbox Code Playgroud)
所以我试着写一个转换器:
public partial class User
{
public static explicit operator Employer(User u)
{
Run Code Online (Sandbox Code Playgroud)
但我得到错误:
Error 21 'User.explicit operator Employer(User)': user-defined
conversions to or from a derived class are not allowed
C:\Users\..\Documents\Visual Studio 2010\Projects\..\Website\Models\EF.Custom.cs
Run Code Online (Sandbox Code Playgroud)
精细.然后我重载了构造函数,Employer如下所示:
public partial class Employer
{
public Employer(User u)
{
this.Id = u.Id;
this.Claims = u.Claims;
// etc.
}
}
Run Code Online (Sandbox Code Playgroud)
并认为我可以这样做:
Employer e = …Run Code Online (Sandbox Code Playgroud) 会有切片的危险吗?
result Compare(const Osp::Base::Object &obj1, const Osp::Base::Object &obj2, int &cmp) const {
cmp = ((const Block)obj1).NumSuperBlocks() - ((const Block)obj2).NumSuperBlocks();
}
Run Code Online (Sandbox Code Playgroud)
哪里
class Block : Object {/*Filler*/}
Run Code Online (Sandbox Code Playgroud)
并obj1和obj2放心是Block对象?
我很想用:
cmp = ((const Block*)&obj1)->NumSuperBlocks() - ((const Block*)&obj2)->NumSuperBlocks();
Run Code Online (Sandbox Code Playgroud)
但在阅读SO的对象切片标签的简要描述时,我很想使用前者.但我真的不想要任何讨厌的无声切片.
我想知道标准对以下代码的安全性的说法:
class A { int v; };
class B: public A { }; // no added data member
A a;
B& b = static_cast<B&>(a);
Run Code Online (Sandbox Code Playgroud)
显然的运行时类型a是A,不是B,所以剧组是不是真的类型安全的.但是,由于没有添加任何成员而且没有任何内容是虚拟的,IMO的类的内存布局应该是相同的,这应该可行(可能写入更好reinterpret_cast以表明这种行为?).我的猜测是这是UB,但适用于任何编译器.或者这实际上定义得很好?还是比较危险?
此外,如果B有一些额外的非虚拟成员方法会有什么变化吗?再一次,直觉上我会说不,但我想知道标准对此有何看法.
class Media {
var name :String = ""
init(name:String) {
self.name = name
}
}
class Song:Media {}
class Movie:Media{}
let s1 = Song(name :"Fireproof")
var m1 :Media = s1 //upcasting
//var s2 :Song = m1
var s2:Song = m1 as Song //down casting
// var x1 :Movie = m1 as Movie //
Run Code Online (Sandbox Code Playgroud)
在行上var m1: Media = s1你可以设置m1等于s1因为m1's类型是超类s1?
在线var s2: Song = m1 as Song,它被认为是"向下铸造",是因为m1: Media并且你"铸造"它"作为"一种 …
在我问我的问题之前,这是我的结构:
public class Data : ScriptableObject {...}
public class ItemData : Data {...}
public class WeaponData : ItemData {...}
public abstract class Item<T> : Visual<T> where T : ItemData {...}
public class Weapon<T> : Item<T> where T : WeaponData {...}
Run Code Online (Sandbox Code Playgroud)
当我创建一个Weapon对象并将其分配给我时,我收到一个错误(无法从源类型转换为目标类型)Item<ItemData>.
Weapon<Foo> weapon = new Weapon<Foo>();
Item<ItemData> other = weapon;
Run Code Online (Sandbox Code Playgroud)
这是为什么?
因此,我正忙于向下转换,试图找到有效的方法和无效的方法。我有三个类:基类Animal和两个派生类Dog和Cat:
private class Animal {
}
private class Dog extends Animal {
}
private class Cat extends Animal {
}
Run Code Online (Sandbox Code Playgroud)
出于明显的原因,编译器不允许以下代码:
Dog dog = s.new Dog();
Cat cat = (Cat) dog;
Run Code Online (Sandbox Code Playgroud)
这是因为我将一个派生类转换为另一派生类,这是不可能的。但是,如果我创建Animal一个接口类型和Cat一个接口类型,那么编译器会突然接受它,即使没有可能,也不会出现任何问题。
private interface Animal {
}
private class Dog implements Animal {
}
private interface Cat extends Animal {
}
Run Code Online (Sandbox Code Playgroud)
一旦运行与以前相同的代码,就会像预期的那样给我一个错误。
downcast ×10
c++ ×5
casting ×4
c# ×3
conventions ×1
generics ×1
inheritance ×1
java ×1
rust ×1
static-cast ×1
swift ×1
swig ×1
upcasting ×1