多重继承和鸭子打字

时间:2009-09-20 00:22:06

标签: c++

在使用Kira3时,我正在玩C ++编译器并寻找实现Kira的鸭子打字的好方法。我希望(因为已经有几年的直接C ++编程)我可以在多种类型下使用多重继承来进行成员访问。唉,到目前为止我都失败了......

理想代码如下:

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)时抛出输入错误。这是超悲伤的表情。我可以通过创建一个类型塔来强制它工作。在上面的例子中,我可以改变     class Point3D:public WithZ,public WithX,public WithY {}; 至     class Point3D:public Point2D,public WithZ {};

现在的问题是我的结构重叠了。我要么在kira代码中抛出一个很难解决的错误,要么让编译器做一些不同的事情。我试过了

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

希望编译器将它们组合起来,但是这会给成员变量带来模糊的访问。这可以通过复制对不明确的成员变量的写入来修复,这可能是我编译阶段的解决方案。此解决方案需要更多内存。

任何想法如何在没有记忆丧失的情况下解决这个问题?

或者,有没有办法将变量转换为多种类型?像

(WithX,WithY *)p

3 个答案:

答案 0 :(得分:8)

我对Kira一无所知,但您至少可以使用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

答案 1 :(得分:3)

重载零点?

void ZeroOut(Point2D * p) { p->x = 0; p->y = 0; };
void ZeroOut(Point3D * p) { /* whatever you want*/ };

答案 2 :(得分:2)

  

我试过......希望编译器将它们组合在一起,但是这会给成员变量带来模糊的访问。

要解决 问题,请尝试virtual inheritance