如何使用继承类中的多态函数参数避免c ++中的类型转换和typeid

时间:2017-04-05 09:39:40

标签: c++ polymorphism function-calls

我有一个抽象的形状类,它扩展了多个实际的形状实现。需要计算不同形状的重叠。起初我想用简单的多态函数参数来做这件事,如代码片段1所示。

#include <iostream>
#include <vector>
#include <typeinfo>
#include <string>

class Shape {
    public:
        virtual void getOverlap(Shape *obj) = 0;
    };

    class Square : public Shape {
        class Circle;
    public:
        virtual void getOverlap(Circle *obj) 
             { std::cout << "Square overlap with Circle" << std::endl; }    
        virtual void getOverlap(Square *obj) 
             { std::cout << "Square overlap with Square" << std::endl; }
};

class Circle : public Shape {
    class Square;
    public:
        virtual void getOverlap(Circle *obj)
            { std::cout << "Circle overlap with Circle" << std::endl; }
        virtual void getOverlap(Square *obj) 
            { std::cout << "Circle overlap with Square" << std::endl; }
};

int main() {
    std::vector<Shape*> shapes = { new Square, new Circle };
    shapes[0]->getOverlap(shapes[1]);
    shapes[1]->getOverlap(shapes[1]);
}

由于继承的类不实现虚函数,而是尝试使用派生类作为参数来实现虚函数,因此这个过程不会编译。但我希望它能使我的意图明确。

第二个代码段中显示了在找不到针对此问题的合适答案后我想到的解决方法。

#include <iostream>
#include <vector>
#include <typeinfo>
#include <string>

class Shape {
public:
    virtual void getOverlap(Shape *obj) = 0;
};

class Square : public Shape {
    class Circle;
public:
    virtual void getOverlap(Shape *obj) {
        string className = typeid(*obj).name();
        if (className.compare("class Circle") == 0){
            getOverlap((Circle*)obj);
        }
        else if (className.compare("class Square") == 0) {
            getOverlap((Square*)obj);
        }
    }

private:
    void getOverlap(Circle *obj) 
        {   std::cout << "Square overlap with Circle" << std::endl; }
    void getOverlap(Square *obj) 
        { std::cout << "Square overlap with Square" << std::endl; }
};

class Circle : public Shape {
    class Square;
public:
    virtual void getOverlap(Shape *obj) {
        string className = typeid(*obj).name();
        if (className.compare("class Circle") == 0) {
            getOverlap((Circle*)obj);
        }
        else if (className.compare("class Square") == 0) {
            getOverlap((Square*)obj);
        }
    }

private:
    void getOverlap(Circle *obj) 
         { std::cout << "Circle overlap with Circle" << std::endl; }
    void getOverlap(Square *obj) 
         { std::cout << "Circle overlap with Square" << std::endl; }
};

int main() {
    std::vector<Shape*> shapes = { new Square, new Circle };
    shapes[0]->getOverlap(shapes[1]);
    shapes[1]->getOverlap(shapes[1]);
}

我非常不喜欢对类的typeid的特定请求以及显式转换为正确的指针类型,因为该对象原则上已经是正确的类型。

使用c ++的多态性,这样做的好方法是什么。

1 个答案:

答案 0 :(得分:1)

您尝试实现的目标称为double dispatch,面向对象的实现方式是Visitor pattern

在你的情况下,它看起来有点像这样:

class Shape
{
   public:
     virtual void getOverlap(Shape* s)=0;

     virtual void getOverlapCircle(Circle* c)=0;
     virtual void getOverlapSquare(Square* s)=0;
};

class Square : public Shape
{
   public:
     virtual void getOverlap(Shape* s)
     {
         s->getOverlapSquare(this);
     }

     virtual void getOverlapSquare(Square* s)
     {
        // code for overlapping 2 squares
     }

     virtual void getOverlapCircle(Circle* c)
     {
        // code for overlapping a circle & a square
     }
};

显然Circle课也是如此。

这是默认的教科书方法;注意它不需要任何演员阵容。

然而,我个人认为它非常难看,因为它完全没有任何重叠形状对称的概念,并且它不容易扩展。

然而,更好的技术需要进行一些低级调整,直到重新实现整个vtable机制为止。