我在http://www.javabeginner.com/learn-java/java-object-typecasting上遇到过这个例子,在谈到显式类型转换的部分中,有一个例子让我感到困惑.
这个例子:
class Vehicle {
String name;
Vehicle() {
name = "Vehicle";
}
}
class HeavyVehicle extends Vehicle {
HeavyVehicle() {
name = "HeavyVehicle";
}
}
class Truck extends HeavyVehicle {
Truck() {
name = "Truck";
}
}
class LightVehicle extends Vehicle {
LightVehicle() {
name = "LightVehicle";
}
}
public class InstanceOfExample {
static boolean result;
static HeavyVehicle hV = new HeavyVehicle();
static Truck T = new Truck();
static HeavyVehicle hv2 = null;
public static void main(String[] …Run Code Online (Sandbox Code Playgroud) 我试图理解Java的多态性,我有一个关于向下转换对象的问题.让我们说这个例子我有两个继承自超类Animal的子类Dog和Cat
根据我的理解,向下转换对象的唯一方法是,如果此Object已经是好的类型,如下所示:
Animal a = new Dog();
Dog d = (Dog) a;
Run Code Online (Sandbox Code Playgroud)
这样可行吗?
但是如果我想在不知道它会是什么的情况下创造一个普通的动物,然后在我知道的时候施放它,我该怎么办呢?
Animal a = new Animal();
Dog d = (Dog) a;
Run Code Online (Sandbox Code Playgroud)
这会在运行时抛出ClassCastException吗?
我发现这样做的唯一方法是创建一个新的Dog构造函数,从常规动物创建一个狗:
Animal a = new Animal();
Dog d = new Dog(a);
Run Code Online (Sandbox Code Playgroud)
同
public Class Dog extends Animal{
public Dog(Animal a){
super(a);
}
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,我该怎么做呢?
非常感谢!nbarraille
令我惊讶的是,gcc 11.2接受此代码,但仅在 C++20 模式下:
struct Base {};
struct Derived : Base { int i; };
int f(Base& b) { return static_cast<Derived>(b).i; }
// ^~~~~~~ oops, forgot the `&`
Run Code Online (Sandbox Code Playgroud)
同样,MSVC 19.29 在 C++20 模式下接受它,在 C++17 模式下拒绝它,但即使在 C++20 模式下,clang 也会拒绝它。
查看汇编器输出,f总是返回0,因此它忽略了Derived传递给的任何潜在的实际数据f。
这是 UB,还是在 C++20 中合法,如果是,为什么?
我已经遇到过这个问题的调整.考虑:
class A {};
class B : private A {
static void foo();
};
void B::foo(){
B* bPtr1 = new B;
A* aPtr1 = dynamic_cast<A*>(bPtr1); // gives pointer
B* bPtr2 = dynamic_cast<B*>(aPtr1); // gives NULL
}
Run Code Online (Sandbox Code Playgroud)
aPtr1事实上,因为它是类型的B*,并且因为我们已经完全访问B并继承了它A,所以我希望两个转换都可以工作.但他们没有; 为什么?还有另一种方法来实现这种演员吗?
注意:
foo()不是B的成员,两个演员都会失败.B从A公开继承,两个演员都可以.我的基类如下:
class point //concrete class
{
... //implementation
}
class subpoint : public point //concrete class
{
... //implementation
}
Run Code Online (Sandbox Code Playgroud)
如何从点对象转换为子点对象?我尝试了以下三种方法:
point a;
subpoint* b = dynamic_cast<subpoint*>(&a);
subpoint* b = (subpoint*)a;
subpoint b = (subpoint)a;
Run Code Online (Sandbox Code Playgroud)
这些演员有什么问题?
我正试图在Rust中操纵AST.会有很多操作,我希望我的树是不可变的,所以为了节省时间,所有引用都将是Rcs.
我的树节点将如下所示:
enum Condition {
Equals(Rc<Expression>, Rc<Expression>),
LessThan(Rc<Expression>, Rc<Expression>),
...
}
enum Expression {
Plus(Rc<Expression>, Rc<Expression>),
...
}
Run Code Online (Sandbox Code Playgroud)
我想用另一个相同类型的节点替换给定类型的随机节点.要在树上进行通用操作,我已经做了一个特性:
trait AstNode {
fn children(&self) -> Vec<Rc<AstNode>>;
}
Run Code Online (Sandbox Code Playgroud)
所有节点都实现了这一点.这允许我通过简单地调用来遍历树而不必为每个操作解构每个节点类型children().
我还希望克隆一个节点,同时只更新其中一个子节点,并保留其他子节点.假设我已经能够生成正确的具体类型的节点(如果我错了,我很高兴程序会出现恐慌).我将在特征中添加以下方法:
trait AstNode {
fn clone_with_children(&self, new_children: Vec<Rc<AstNode>>) -> Self
where Self: Sized;
}
Run Code Online (Sandbox Code Playgroud)
我的计划是把孩子们带回来childen(),替换他们中的一个,然后调用clone_with_children()构建一个相同枚举变量的节点,但是替换了一个节点.
我的问题是如何写clone_with_children().
我需要向下转换Rc<AstNode>到Rc<Expression>(或你有什么),同时保持内部的引用计数Rc相同,但没有我已经找到了向下转换库似乎是能够做到这一点.
我想要的是什么,或者我应该完全不同地做到这一点?
protocol P : class {
var value:Int {get}
}
class X : P {
var value = 0
init(_ value:Int) {
self.value = value
}
}
var ps:[P] = [X(1), X(2)]
for p in ps {
if let x = p as? X { // works for a single variable
...
}
}
if let xs = ps as? [X] { // doesn't work for an array (EXC_BAD_ACCESS)
...
}
Run Code Online (Sandbox Code Playgroud)
如果P是类而不是协议,则代码正常工作.类和协议之间有什么区别?它们都是作为堆中的指针实现的,不是吗?上面的代码可以成功编译,但在运行时崩溃.这个EXC_BAD_ACCESS错误是什么意思?
感谢@Antonio,但我仍然不明白这个示例代码是如何工作的.
let someObjects: [AnyObject] = [
Movie(name: "2001: A …Run Code Online (Sandbox Code Playgroud) 这两个代码片段之间的区别是什么:
let cell = tableView.dequeueReusableCellWithIdentifier("cellId") as UITableViewCell?
// vs
let cell = tableView.dequeueReusableCellWithIdentifier("cellId") as? UITableViewCell
Run Code Online (Sandbox Code Playgroud)
结果不完全一样吗?
考虑以下类:
template <class Derived>
class BaseCRTP {
private:
friend class LinkedList<Derived>;
Derived *next = nullptr;
public:
static LinkedList<Derived> instances;
BaseCRTP() {
instances.insert(static_cast<Derived *>(this));
}
virtual ~BaseCRTP() {
instances.remove(static_cast<Derived *>(this));
}
};
Run Code Online (Sandbox Code Playgroud)
struct Derived : BaseCRTP<Derived> {
int i;
Derived(int i) : i(i) {}
};
Run Code Online (Sandbox Code Playgroud)
int main() {
Derived d[] = {1, 2, 3, 4};
for (const Derived &el : Derived::instances)
std::cout << el.i << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我知道,这是不确定的行为来访问的成员Derived在BaseCRTP<Derived>构造函数(或析构函数),因为Derived构造函数执行后的BaseCRTP<Derived>构造(和析构函数的其他方式)。
我的问题是:在不访问任何成员的 …
请考虑以下大纲:
class Base { /* ... */ };
class Derived : public Base
{
public:
void AdditionalFunctionality(int i){ /* ... */ }
};
typedef std::shared_ptr<Base> pBase;
typedef std::shared_ptr<Derived> pDerived;
int main(void)
{
std::vector<pBase> v;
v.push_back(pBase(new Derived()));
pDerived p1( std::dynamic_pointer_cast<Derived>(v[0]) ); /* Copy */
pDerived p2 = std::dynamic_pointer_cast<Derived>(v[0]); /* Assignment */
p1->AdditionalFunctionality(1);
p2->AdditionalFunctionality(2);
/* A */
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里我用扩展功能(AdditionalFunctionality方法)的派生类扩展基类.
第一个问题,这样可以吗?我已经阅读了很多问题,说这不合适,你应该在基类中声明附加功能(通常建议在基类中使它们成为纯虚方法).但是,我不想这样做.我想扩展基类的功能,而不仅仅是以不同的方式实现它.有没有更好的解决方案来实现这一目标?
好的,所以在这段代码中我也使用一个STL容器来存储这些指针,这些指针允许我存储指向Base类型对象的指针以及Derived类型的对象而不切片对象.
第二个问题,这是有道理的,对吗?事实上,我通过使用指向基类对象的指针而不是基类对象本身来避免切片?
如果我"知道"某个指针指向Derived对象,那么我将使用它std::dynamic_pointer_cast来转换智能指针.
第三个问题,这个编译没有任何警告和工作,但它是否安全?有效?它是否会打破共享指针的引用计数方面,并且在我预期之前无法访问delete我的对象或delete它们?
最后,我可以使用复制构造函数或通过赋值执行此转换,如p1和p2所示.这样做是否有首选/正确的方法?
类似的问题:
downcast ×10
c++ ×5
casting ×3
inheritance ×2
java ×2
swift ×2
arrays ×1
c++20 ×1
cocoa ×1
crtp ×1
oop ×1
private ×1
protocols ×1
rust ×1
shared-ptr ×1
static-cast ×1
stl ×1
type-systems ×1