2013-03-29 183 views
0

我在程序中遇到了设计问题,因为我需要偶尔访问所有存储在基类指针向量中的子类的属性&。我的代码看起来是这样的:访问C++子类的属性/功能

class B1; 
class B2; 
class Base { 
    private: 
    int id, a, b; 

    public: 
    virtual int getA() { return a; } 
    virtual int getB() { return b; } 
    virtual B1 *getB1() { return NULL; } //seems like a bad idea 
    virtual B2 *getB2() { return NULL; } //to have these two functions 
    Base(int newId) { id = newId; } 
}; 

class B1 : public Base { 
    private: 
    int x; 

    public: 
    int getX() { return x; } 
    B1 *getB1() { return this; } 
}; 

class B2 : public Base { 
    private: 
    int y; 

    public: 
    int getY() { return y; } 
    B2 *getB2() { return this; } 
}; 

class Thing { 
    private: 
    std::vector<Base*> bases; 

    void addBase(Base *base) { bases.push_back(base); } 
    void doB1Stuff(); 
    void doB2Stuff(); 
    void setAandB(int ID, int newA, int newB); //set a and b of one of the elements in bases vector based upon the id given 
}; 

的问题是,如果我需要访问X或Y的东西,像下面这样:

void Thing::doB1Stuff() { 
    for(std::vector<Base*>::iterator it = bases.begin(); it != bases.end(); ++it) { 
    if (it->getB1()) { 
     //do stuff with b1 
    } 
    } 
} 

上面的代码应该工作,但如果它似乎坏主意,因为人们很容易忘记检查,如果指针为空使用这样的B1/B2属性之前:

void Thing::doB2Stuff() { 
    for(std::vector<Base*>::iterator it = bases.begin(); it != bases.end(); ++it) { 
    std::cout << it->getY(); //I believe this will crash the program if a NULL pointer is returned 
    } 
} 

我的问题因此是:什么是访问的子类属性的好办法吗?我正在考虑为Thing中的B1和B2使用两个单独的向量,但这似乎并不是一个好主意,因为我需要能够轻松设置a和b。有什么想法吗?

+0

如果您的类在上下文中表现出根本性不同,则不应将它们混合在数组中。也许你想使用模板呢? – Dave

+1

您的确切问题已通过'dynamic_cast'解决。 (或更好的设计) –

回答

0

您可以检查您正在访问的项目是否是您正在寻找的正确的子类别类型,但要执行此操作,您需要包含运行时类型信息(rtti)。

然后,如果它是某种类型而不是null,则可以将其转换为该类型并调用正确的函数。

你也可以使用dynamic _cast,虽然为了这个工作你需要再次rtti,它基本上与检查自己,然后静态铸造相同。

1

你有什么是完美的罚款:只要你不存储NULL S IN指针bases载体,就没有必要为空,检查值从迭代器返回。不幸的是,一个指针向量是你的多态对象容器的唯一选择。您可以创建一个共享指针向量来简化处理删除操作,但基本想法将保持不变。

+0

+1最后一句中的'subst(“can”,“should”)'= P – WhozCraig

0

你说得对,这不是接近问题的好方法,你可以使用dynamic_cast有一个安全的方式来确定要使用哪个对象,但是这是不好的代码的气味给我。

我会做什么,而不是访问子属性是创建一个虚拟函数,返回您想要在基类中的值。

例子:

class Base { 
    private: 
    int id, a, b; 

    public: 
    virtual int getA() { return a; } 
    virtual int getB() { return b; } 
    virtual int getSubValue() = 0; // 
    Base(int newId) { id = newId; } 
}; 

class B1 : public Base { 
    private: 
    int x; 

    public: 
    int getSubValue() { return x; } 
}; 

class B2 : public Base { 
    private: 
    int y; 

    public: 
    int getSubValue() { return y; } 
}; 

然后,你可以调用它 - > getSubValue()来获得您所请求的子值。

这是我的观点,有很多方法可以解决这个问题,但这是我建议根据您提供的信息提出的建议。