C++类型转换自定义类的非指针实例

3

假设我有一个类A,它有一个子类B。

class A 
{
public:
    A(){};
}

class B : public A
{
public:
    B(int value){ foo = value };
    int foo;
}

B是A的子类,具有一个整型属性foo。

现在假设我按照下面这样做:

std::vector<A> mylist;
B myB(5); //Create a new instance of class B
mylist.push_back(myB); //Add b to my vector of A.

现在我想访问mylist中的一个元素,并将其强制转换为类型B并检索'foo'。以下做法是否合法?
B *instance = (B *)&mylist[0]; 

我在我的项目中尝试过这样做,但是如果我打印出foo的值,它会是不正确的:

std::cout<<instance->foo<<std::endl; // This does not give me 5. It gives me a garbage number.

问题的根源在于我不知道在C++中如何正确地转换非指针。

好的,现在假设我这么做:不要这样做。既然你不应该那样做,你的问题的剩余部分也就没有意义了。 - PaulMcKenzie
1
那么我正在尝试找出将非指针转换的正确方法... - user1855952
可能是什么是C++中的切片问题?的重复。 - n. m.
如果您的向量保存A对象,那么它只应该知道A对象。假设您现在将向量更改为保存A对象的指针。仍然,向量应该只知道A指针,并且您应该仅使用A接口工作。因此,我的意思是您应该重新考虑设计。也许要引入虚函数。 - PaulMcKenzie
没有正确的方式。 - n. m.
2个回答

4
当你写mylist.push_back(myB)时,会发生切片mylist 存储 A 对象。因此,发生的情况是将你的B转换为一个A,失去了所有不属于A的东西。只有A被存储。你无法检索到丢失的部分。
这与执行以下操作相同:
B myB(5);
A a(myB);

为了实现多态行为,你需要将A定义为一个多态类,并且通过指针来引用对象,即A *
因此,你需要在A中添加至少一个虚函数(虚析构函数是个不错的选择),并且使用指针存储向量。例如:
std::vector< A* > mylist;
mylist.push_back( new myB(5) );
B *instance = dynamic_cast<B *>(mylist[0]);

现在这段代码是可行的,但你必须非常小心地删除你创建的内存。为了解决这个问题,有一个被引用计数的指针shared_ptr 可以帮助你。我编写了以下测试案例,似乎可以工作(免责声明 - 我不是智能指针多态性方面的专家,所以我希望这里没有隐蔽的错误)。
#include <iostream>
#include <memory>
#include <vector>

class A 
{
public:
    A(){};
    virtual ~A() {}
};

class B : public A
{
public:
    B(int value): foo(value) {}
    int foo;
    ~B() { std::cout << "Destructor B(" << foo << ")" << std::endl; }
};

int main()
{
    std::vector< std::shared_ptr<A> > mylist;

// Test the polymorphic behaviour
//  mylist.push_back( std::make_shared<A>() );

// create directly into container
    mylist.push_back( std::make_shared<B>(5) );

// via pointer
    B *temp_b = new B(6);
    mylist.push_back( std::shared_ptr<B>(temp_b) );

    std::shared_ptr<B> instance  = std::dynamic_pointer_cast<B>( mylist[0] );
    if ( !instance )
       std::cout << "Item was not a B" << std::endl;
    else
       std::cout << instance->foo << std::endl;
} 

2

这是C++中典型的切片问题。

你应该将指针存储在向量中,以便轻松避免它们。如果您不想处理原始指针,请使用智能指针。


什么是切片?有没有一种方法可以在不使用指针的情况下完成它? - user1855952
@lizusek:不过,类型字段会如何帮助呢?当推送时仍然会发生分片。 - László Papp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接