Inheritance 你不是像我想的那样工作吗?

Inheritance 你不是像我想的那样工作吗?,inheritance,casting,polymorphism,Inheritance,Casting,Polymorphism,我有一个处理汽车贴花信息的超类。我有一个子类处理事务的特定贴花信息。我在事务标记中有一个特殊的覆盖,用于在设置标记之前检查某些事项。我遇到的问题是,有时我需要获取有关通用贴花对象的信息,并将其设置为我的事务贴花。例如: TransactionDecal myTransactionDecal = new TransactionDecal(); Decal myGenericDecal = new Decal(); myTransactionDecal = (TransactionDecal) my

我有一个处理汽车贴花信息的超类。我有一个子类处理事务的特定贴花信息。我在事务标记中有一个特殊的覆盖,用于在设置标记之前检查某些事项。我遇到的问题是,有时我需要获取有关通用贴花对象的信息,并将其设置为我的事务贴花。例如:

TransactionDecal myTransactionDecal = new TransactionDecal();
Decal myGenericDecal = new Decal();
myTransactionDecal = (TransactionDecal) myGenericDecal.getGenericDecal();

但是我得到一个运行时错误,告诉我不能在类型之间进行强制转换。我到底做错了什么?这是正确的方法吗?谢谢

可替代性原则表明,任何类型都可以由自身或子类型替代

这里,您正在做相反的操作-您正在尝试在子类型的变量中引用超类型的实例(假设seap是超类,transactionseap是子类)


这是被阻止的,因为存在继承来专门化现有的类,即扩展接口;通常,替换超类会限制接口,这将允许调用(通过引用变量类型)在超类中未实现的方法。

您不能这样做,因为您会将不太专业的类(贴花)强制转换为更专业的类(Transaction贴花)。这是行不通的,因为现在你可以在贴花上调用没有在那里实现的方法(想想Transaction贴花中新引入的变量,这些变量被新方法或重写的方法使用),它们不可能存在于贴花的实例中。

Jeremy对这不起作用的解释是关于钱的

如果您想避开此问题,可以使TransactionLabr不从贴花继承,而是包含贴花的实例。这样,您可以将内部实例设置为通用贴花,而不会丢失任何事务数据


当然还有其他模式,但这是处理这类问题的比较流行的模式之一

这称为向下投射。这是一个很好的时间,当它是好的,当它不是(在C#反正)

此代码将成功编译。 在运行时,cast操作符 执行检查以确定 所指的对象确实是有价值的 输入Bird。如果不是,则运行时 引发InvalidCastException

但是,你不应该这样做。派生类型应该能够完成基类型所能做的一切。如果您有一个基类型,并且想要一些只有派生类型才能做的事情,那么您最好得到一个派生类型的实例来完成它!:)

按注释编辑:没有理由不能提供一个派生构造函数,该构造函数接受一个基实例并围绕该实例构建一个派生构造函数(如围绕特定基的默认派生构造函数)


但是,在我看来,您需要一个接口,或者您应该放松对方法参数的要求。毕竟,如果你的方法可以很好地对动物进行操作,那么就没有理由强迫你将一只鸟交给它,而这正是你的方法所要做的。

使用你的示例,下面是多态性的实现方式:

// cast derived object as base object
Decal myGenericDecal = null;
TransactionDecal myTransactionDecal = TransactionDecal.GetTransactionDecal()
myGenericDecal = myTransactionDecal;

// cast base object to a derived object
TransactionalDecal newTransactionalDecal = null;
newTransactionalDecal = (TransactionalDecal)myGenericDecal;

这取决于您想对MyTransaction贴花执行什么操作,特别是是否需要Transaction贴花的数据成员。添加一个构造函数怎么样

TransactionDecal::TransactionDecal(const Decal &);

或者只是将您想要的功能移动到贴花中,或者移动到非成员函数中?

我认为添加类定义将有助于解决这个问题。VB.NET最新版本。错误消息是:无法将类型为“贴花”的对象强制转换为类型为“Transaction贴花”。为什么要对贴花执行GetGeneric贴花()?它不应该只是MyTransaction贴花=(Transaction贴花)MyGeneric贴花;我同意卡博特的观点,添加你的类定义。getgnericdeal()方法只是一个例子,因为我实际上使用了一个方法来获取通用贴花。对不起,应该说得更清楚些。所以我真正拥有的是:MyTransaction贴花=GetGeneric贴花();好的,这里有一个更新,我想我可以更好地总结我的问题。我的特定TransactionSeal类上的属性具有特定的setter约束。因此,当我尝试将其转换为一个基时,它会工作,但我失去了setter约束功能,因为它只使用基的方法。啊,我明白你的意思。那么解决办法是什么呢?我应该制作一个适配器,它只接受超类的值并将它们设置为子类的值。不过,这似乎不太实际。必须有某种方法来做到这一点。父对象的属性对子类可见吗?是公共的还是通过mutator方法?或者您是否需要从父级读取静态值?我不知道为什么在不需要新对象的情况下不能从子类访问这些值?另一种可能是将业务规则卸载到一个“事务”实例中,并给它一个与特定贴花实例的“has-a”关系(聚合)。Jeremy,请阅读我在JP帖子中的评论。我想我已经明白我真的不需要在这里施展才华了。谢谢,除了杰里米的解决方案之外,其他一切都让我意识到我做错了什么。因为他说强制转换只能更改变量的值,所以我开始考虑我正在使用的克隆方法。克隆时,我创建了一个新的贴花,将其属性设置为当前实例,然后尝试将其强制转换为Transaction贴花。这是行不通的,因为我在克隆方法中说了“New deal()”。相反,我创建了一个复制方法,该方法将任何类型的贴花作为参数并设置其道具。这样,我仍然可以使用它的特殊二传手,因为我没有铸造到一个基础类型。谢谢。这让我想到了一件事——实际上我需要强制转换的唯一原因是因为我需要基的实际属性值。我仍然想保留子类上所有的专用方法调用,所以我真的不认为
// cast derived object as base object
Decal myGenericDecal = null;
TransactionDecal myTransactionDecal = TransactionDecal.GetTransactionDecal()
myGenericDecal = myTransactionDecal;

// cast base object to a derived object
TransactionalDecal newTransactionalDecal = null;
newTransactionalDecal = (TransactionalDecal)myGenericDecal;
TransactionDecal::TransactionDecal(const Decal &);