如何在给定指向派生类型的指针的情况下有条件地将指针转换为基类型

时间:2014-10-29 18:43:29

标签: c++ pointers casting

我有两个来自基类Triangle的派生类SphereShape

我遇到的情况是我在类Shape*中存储了一个基类指针A,并为每个派生类型A提供了两个类doSomething(Sphere* sp)的重载成员函数}和doSomething(Triangle* tr)

class Shape
{
public:
    Shape() {};
    virtual ~Shape() = 0;
};

class Triangle : public Shape
{
public:
    Triangle();
};

class Sphere : public Shape
{
public:
    Sphere();
};

class A
{
private:
    Shape* shape;
    void doSomething(Triangle* tr);
    void doSomething(Sphere* sp);
public:
    A();
    ~A();
};

但是,当我尝试通过将Shape*类型的指针传递到doSomething函数来运行我的代码时,我收到以下错误:

candidate function not viable: cannot convert from base class pointer 'value_type'
      (aka 'Shape *') to derived class pointer 'const Triangle *' for 1st argument
void A::doSomething(Triangle* tr) {

Sphere的相同消息。我也确定虽然是Shape *类型的指针,但它实际上指向了一个派生对象。

那么,如何在不修改TriangleSphere类且仅修改A的情况下解决此问题?

3 个答案:

答案 0 :(得分:3)

在C ++中无法做到这一点。进行动态调度的唯一方法是调用虚方法:

shape->doSomething();

Triangle::doSomethingSphere::doSomething可能是虚拟Shape::doSomething的不同实现。

因此,您需要更改代码结构,以便控制调用的shape本身。或者......你可以拥有一个巨大的分支,你可以依次尝试每个分支:

void doSomething() {
    if (Triangle* t = dynamic_cast<Triangle*>(shape)) {
        doSomething(t);
    }
    else if (Sphere* s = dynamic_cast<Sphere*>(shape)) {
        doSomething(s);
    }
    // etc.
}

我建议不要这样做。除了可怕的阅读之外,它也很慢而且不可维护。

答案 1 :(得分:2)

您需要使用dynamic_cast找出Shape*所指向的派生类并获取指向该类的指针,然后您可以将该指针传递给doSomething()重载。需要,例如:

class A
{
private:
    Shape* shape;
    void doSomething(Shape* sh);
    void doSomething(Triangle* tr);
    void doSomething(Sphere* sp);
public:
    A();
    ~A();
};

void A::doSomething(Shape* sh)
{
    if (Sphere *sp = dynamic_cast<Sphere*>(sh))
        doSomething(sp);

    else if (Triangle *tr = dynamic_cast<Triangle*>(sh))
        doSomething(tr);
}

答案 2 :(得分:-1)

必须有一些决策过程才能在球体或三角形之间进行选择。

如果您在编译时确定了所需的形状,则可以保留您的设计,并使用部分模板专业化。 (此示例已使用g ++ 4.7.2编译)

#include <iostream>

using std::cout;
using std::endl;

struct Shape
{
};

struct Sphere : Shape
{
    double radius;
    Sphere(double radius): radius(radius) {}
};

struct Triangle : Shape
{
    double a, b, c;
    Triangle(double a, double b, double c): a(a), b(b), c(c) {}
};

void foo(Sphere * b)
{
    cout << "Sphere " << b->radius << endl;
};

void foo(Triangle * c)
{
    cout << "Triangle " << c->a << ',' << c->b << ',' << c->c << endl;
};

template<bool>
struct ShapeShifter
{
};

template<>
struct ShapeShifter<true>
{
    typedef Sphere* Type;
};

template<>
struct ShapeShifter<false>
{
    typedef Triangle* Type;
};

int main()
{
    Shape * a1 = new Sphere(1.5);
    Shape * a2 = new Triangle(3,4,5);
    const int x = 0;

    foo(static_cast<ShapeShifter<x == 0>::Type>(a1));
    foo(static_cast<ShapeShifter<x != 0>::Type>(a2));
}

否则你可以指出使用dynamic_cast