基于派生类的类型转换

时间:2009-08-13 22:14:55

标签: c++ class dynamic casting

我有一个基类:

class RedBlackTreeNode
{
// Interface is the same as the implementation
public:
    RedBlackTreeNode* left;
    RedBlackTreeNode* right;
    RedBlackTreeNode* parent;
    Color color;
    TreeNodeData* data;

    RedBlackTreeNode():
        left(0),
        right(0),
        parent(0),
        color(Black),
        data(0)
    {
    }
    // This method is to allow dynamic_cast
    virtual void foo()
    {
    }
};

并从中得出一个:

class IndIntRBNode : public RedBlackTreeNode
{
public:
    IndIntRBNode* left;
    IndIntRBNode* right;
    IndIntRBNode* parent;
    IndexedInteger* data;
    IndIntRBNode():
        RedBlackTreeNode(),
        left(0),
        right(0),
        parent(0),
        color(Black),
        data(0)
    {
    }
};

root()和rootHolder在RedBlackTree类中定义:

class RedBlackTree 
{
public:
    RedBlackTreeNode rootHolder;
    RedBlackTreeNode* root()
    {
        return rootHolder.left;
    }
    ...
}

然后我试图进行类型转换:

IndIntRBNode *x, *y, *z;

z = dynamic_cast<IndIntRBNode*>(root());

“z”只是变为零指针,这意味着类型转换失败了。 那么它有什么问题,如何修复它以便能够引用“z”作为指向IndIntRBNode的指针?

补充:rootHolder.left的初始化是某种形式:

    int n = atoi(line + i);

    tree.clear();
    int j = 0;
    if (n > 100)
    {
        n = 100;        // Maximum 100 nodes
    }
    while (j < n)
    {
        IndexedInteger num(j,j + 10);
        RedBlackTreeNode* node;
        int c = tree.search(&num, tree.root(), &node);
        if (c != 0)
        { // if value is not in the tree
            IndexedInteger* v = new IndexedInteger(num);
            tree.insert(node, v, c);
            ++j;
        }
    }

换句话说,它是通过“insert”方法以“while”的第一次迭代初始化的:

void RedBlackTree::insert(
    RedBlackTreeNode* parentNode,
    TreeNodeData* v,
    // If it's negative, then add as the left son, else as the right
    int compare
)
{
    assert(parentNode != 0 && compare != 0);
    RedBlackTreeNode* x = new RedBlackTreeNode;
    x->data = v;
    x->parent = parentNode;
    // If it's root
    if (parentNode == &rootHolder)
    {
        // Then it must be black
        x->color = Black;
    }
    else
    {
        // Leaf must be red
        x->color = Red;
    }
    if (compare < 0)
    {
        // Insert the node as the left son
        assert(parentNode->left == NULL);
        parentNode->left = x;
    }
    else
    {
        // Insert the node as the right son
        assert(parentNode != &rootHolder && parentNode->right == NULL);
        parentNode->right = x;
    }

    ++numNodes;

    if (x != root())
    {
        rebalanceAfterInsert(x);
    }
}

实际上是问题所在:“insert”在语法上创建了RedBlackTreeNode,因此它不能是IndIntRBNode。 我真的已经错误地初始化了,但是我怎样才能派出基类而不是从头开始编写它的整个实现只是为了改变类型? 我是否真的必须覆盖派生类中的所有“类型相对”方法?它似乎非常愚蠢,我认为应该有另一种方式 - 类派生和类型转换的东西,不是吗?

4 个答案:

答案 0 :(得分:2)

您确定RedBlackTree :: rootHolder.left已初始化吗?

我认为你在某处初始化了IndIntRBNode :: left,但当你访问RedBlackTree :: rootHolder.left时,你正在访问RedBlackTreeNode :: left,这不是同一个字段。

答案 1 :(得分:0)

等等..你有一个派生类,其类型与基类相同。这甚至如何编译?

rootHolder.left是如何初始化的?因为如果dynamic_cast失败,那么它不是IndIntRBNode类型。

基本上你没有提供足够的代码来看你正在做什么是错的,但是你做错了。

答案 2 :(得分:0)

如果我正确地阅读了您的代码,您根本不会将rootHolder.left设置为IndIntRBNode指针,而是设置为RedBlackTreeNode

此外,您不需要为多态构成无用的虚函数;只需将析构函数声明为virtual并提供一个空实现。您对多态性的使用也不是很好,因为IndIntRBNode成员会隐藏RedBlackTreeNode成员,所以他们可能会指出不同的事情,具体取决于您是否通过IndIntRBNode访问它们指针/引用或RedBlackTreeNode指针/引用。

答案 3 :(得分:0)

无论您的示例代码可能有或没有其他任何缺陷,它的编写方式似乎都会误解继承和转换的工作方式。我建议您选择一本您选择的C ++书籍并阅读它。

特别是,您应该知道每个对象都是一个且只有一个类型。创建对象后,它永远不会更改类型。转换指针不会将对象从一种类型转换为另一种类型,也不会创建新类型的新对象。 Casting允许您根据指定的类类型处理现有对象,但前提是该对象已经该类,或者是从该类派生的类。

当前你有这一行:

z = dynamic_cast<IndIntRBNode*>(root());

试试这个:

RedBlackTreeNode* other_z = root();

如果 other_z 不为NULL,则root()不是IndIntRBNode,并且世界上所有的dynamic_casting都不会将其变为一个。