c ++重新定义子类和切片中的类型

时间:2011-03-21 12:55:06

标签: c++ oop type-slicing

#include <string>
#include <iostream>

class a { public: int x;};
class b : public a  {public: int x; } ;

int main()
{
    b bee;
    bee.x = 3;

    a ay = bee;
    std::cout << std::endl << ay.x << std::endl;


}

上面的代码在clang 3.0和g ++ 4.5中编译得很好。但是输出是垃圾( - 即,而不是三个)。由于编译器似乎不介意,我如何让代码行为?

其次,如果有某种方法可以使上面的切片/转换正常工作,那么如果我做了以下操作会有多糟糕,只要有充分的理由存在:

class c : public a { public: uint64_t x; };

为什么我对这些语义感兴趣。

我想这样做的原因是这个。我有两个类heirachies,其中一个heirarchy(父级)在相同的层次级别上聚合来自另一个(孩子)的对象。我使用自定义容器进行聚合。我想在父类中键入容器(typedef具有相同的名称),并声明容器在父级的每个级别处使用相同的名称。

类heirarchies旨在包含较低级别的较少信息(基类保持最少),因此切片在这里非常有意义。

修改

你去了,这应该清楚了。

class A { int x; }; 
class B : public A {int y;};
class Ap {std::vector<A> entries;};
class Bp : Ap{std::vector<B> entries;};

子B的成员多于子类A.但是,我不想为只对A类成员感兴趣的代码提供统一的接口。

4 个答案:

答案 0 :(得分:2)

如果直接设置b::x,则无法执行此操作。 a::xb::x是两个不同的成员,后者隐藏了前者。

您仍然可以使用a::x访问类型为b的对象上的static_cast<a&>(bee).x = 3,但基本问题是a::xb::x上的值<{1}}类型的对象未同步。

如果使用“属性getter / setter”抽象对b成员的访问权限,则可以在派生类上安排setter以更新基类的成员。或者(也许这更合适?)您可以创建基类x的成员并直接在派生类中使用它,在从getter返回之前切换。

答案 1 :(得分:1)

嗯!它有点复杂没有?

你为什么不使用:

class a
{
virtual void set( int value ) { x = value; }

protected :
    int x;
};

class b : public a 
{
virtual void setA( int value ) { a::x = value; }

virtual void setA( int value ) { b::x = value; }

virtual void setA( int value ) { a::x = value; b::x = value; }

protected:
    int x;
} ;

构建软件设计有两种方法;一种方法是使其变得如此简单以至于显然没有缺陷,另一种方法是使其变得如此复杂以至于没有明显的缺陷。第一种方法要困难得多。 C.A.R.Hoare

答案 2 :(得分:0)

根据Jon的回答,由于a :: x和b :: x是单独的变量,因此b :: x掩盖了a :: x,如果你想获得正确的语义,你需要提供一个复制转换构造函数。以下代码可以解决问题。

#include <string>
#include <iostream>

class b;

class a { 
public: 
    a();
    a(const b & bee);

    int x;
};
class b : public a  {public: int x; } ;


a::a() {}
a::a(const b & bee)
{ 
        x = bee.x;
}  

int main()
{
    b bee;
    bee.x = 3;

    a ay = bee;
    std::cout << std::endl << ay.x << std::endl; 
}

答案 3 :(得分:0)

也许尝试这样的事情:

class A { int x; }; 
class B : public A {int y;};
class Ap {
public:
    void Append(A *pa)
    {
        entries.push_back(pa);
    }
    A *GetA(size_t nIndex) 
    {
        return entries.at(nIndex);
    }
private:
    std::vector<*A> entries;
};
class Bp : Ap
{ 
public:
    B *GetB(size_t nIndex) 
    {
        return dynamic_cast<B*>(GetA(nIndex));
    }
};