代码之家  ›  专栏  ›  技术社区  ›  MathGladiator

多重继承与Duck类型

c++
  •  2
  • MathGladiator  · 技术社区  · 16 年前

    理想的代码如下所示:

    class WithX { public: int x; };
    class WithY { public: int y; };
    class WithZ { public: int z; };
    
    class Point2D : public WithX, public WithY { };
    class Point3D : public WithZ, public WithX, public WithY { };
    
    void ZeroOut(Point2D * p) { p->x = 0; p->y = 0; };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        Point3D* p = new Point3D();
        p->x = 1;
        p->y = 1;
        p->z = 1;
        ZeroOut(p);
        return 0;
    }
    

    但是,它在调用ZeroOut(p)时抛出一个键入错误。这是一张极度悲伤的脸。我可以通过创建一个类型塔来强制它工作。在上面的例子中,我可以改变 类Point3D:public with z,public with x,public with y{}; 类Point3D:public Point2D,public with z{};

    class Point3D : public Point2D, public WithZ, public WithX, public WithY { }; 
    

    希望编译器能将它们结合起来,但这会使成员变量的访问变得模棱两可。这可以通过将写操作复制到不明确的成员变量来解决,这可能是在编译阶段的一个解决方案。此解决方案需要更多内存。

    或者,有没有一种方法可以将变量强制转换为多种类型?喜欢

    (WithX,WithY *)p
    
    3 回复  |  直到 16 年前
        1
  •  8
  •   Mark Rushakoff    16 年前

    我对基拉一无所知,但你至少可以解决 这一点 质疑 a template function --这有点像 编译时 在某种程度上,鸭子打字。

    #include <iostream>
    class WithX { public: int x; };
    class WithY { public: int y; };
    class WithZ { public: int z; };
    
    class Point2D : public WithX, public WithY { };
    class Point3D : public WithZ, public WithX, public WithY { };
    
    // As long as we pass in a type that has an x and a y member,
    // ZeroOut will compile and run correctly, setting x and y to zero.
    template <typename T>  
    void ZeroOut(T * p) { p->x = 0; p->y = 0; };
    
    int main(int argc, char* argv[])
    {
        Point3D* p = new Point3D();
        p->x = 1;
        p->y = 1;
        p->z = 1;
        ZeroOut(p);
        std::cout << p->x << " " << p->y << " " << p->z << std::endl;
        return 0;
    }
    

    正确输出:

    $ ./a.out
    0 0 1
    

    您在一篇评论中提到,它使用了更多的代码——我想指出,添加的代码可以忽略不计。我将主要功能更改为:

    int main(int argc, char* argv[])
    {
        Point3D* p = new Point3D();
        p->x = 1;
        p->y = 1;
        p->z = 1;
        ZeroOut(p);
    #ifdef USE_2D
        Point2D *q = new Point2D();
        q->x = 1;
        q->y = 1;
        ZeroOut(q);
    #endif
        std::cout << p->x << " " << p->y << " " << p->z << std::endl;
        return 0;
    }
    

    通过这种方式编译,可以得到:

    $ g++ p.cpp -o just3
    $ g++ p.cpp -DUSE_2D -o 3and2
    $ wc -c *3*
     9949 3and2
     9908 just3
    19857 total
    

    您真的要在可执行文件中对41字节的差异进行分析吗?如果是,只需打开优化:

    $ g++ -O2 p.cpp -o just3
    $ g++ -O2 p.cpp -DUSE_2D -o 3and2
    $ wc -c *3*
     9882 3and2
     9882 just3
    19764 total
    
        2
  •  3
  •   Patrick    16 年前

    过载归零?

    void ZeroOut(Point2D * p) { p->x = 0; p->y = 0; };
    void ZeroOut(Point3D * p) { /* whatever you want*/ };
    
        3
  •  2
  •   ChrisW    16 年前

    我试过。。。希望编译器能将它们结合起来,但这会使成员变量的访问变得模棱两可。

    解决 那个 有问题,试试看 virtual inheritance