C ++设计问题:使用各种抽象基类映射

时间:2015-02-15 03:17:20

标签: c++ class c++11 derived-class abstract-base-class

我面临设计问题,可以使用一些外部输入。我试图避免抽象基类转换(因为我听说这很糟糕)。

问题归结于这种结构:

class entity... (base with pure virtual functions)
class hostile : public entity... (base with pure virtual functions)
class friendly : public entity... (base with pure virtual functions)
// Then further derived classes using these last base classes... 

最初我以为我会逃避:

const enum class FactionType : unsigned int
{ ... };

std::unordered_map<FactionType, std::vector<std::unique_ptr<CEntity>>> m_entitys;

并且...我做了但是这导致了我的问题,因为我需要从敌对或友好的角度访问“独特”功能。

我有可耻的尝试(工作但不喜欢它也感觉不安全):

// For-Each Loop: const auto& friendly : m_entitys[FactionType::FRIENDLY]
CFriendly* castFriendly = static_cast<CFriendly*>(&*friendly);

我希望/尝试维护使用unordered_map作为基本抽象类类型的键的FactionType设计......无论如何,非常感谢输入。

如果有任何语法错误,我道歉。

1 个答案:

答案 0 :(得分:0)

关于演员我同意@rufflewind。演员阵容意味着不同的东西,并且在不同的时间都很有用。

要在编译时强制内存区域(无论如何都要在编译时决定输入)使用static_cast。无论正确行为如何,T *另一端的内存量等于sizeof(T)都将被解释为T.

dynamic_cast的决策完全在运行时完成,有时需要RTTI(运行时类型信息)。它做出决定,它将返回一个空指针或一个有效的指针,如果可以做出一个。


这个决定不仅仅是演员表的类型。使用数据结构来查找类型和方法(成员函数)会强加时间约束,与相对快速和强制转换相比,这些时间约束是不存在的。有一种方法可以跳过数据结构,但不会在没有重大重构的情况下进行转换(通过重大重构可以做任何事情)。

你可以将演员表移动到实体类中,让它们正确完成,然后将它们封装在那里。

class entity
{
    // Previous code
    public:

    // This will be overridden in hostiles to return a valid 
    // pointer and nullptr or 0 in other types of entities
    virtual hostile* cast_to_hostile() = 0
    virtual const hostile* cast_to_hostile() const = 0

    // This will be overridden in friendlies to return a valid 
    // pointer and nullptr or 0 in other types of entities
    virtual friendly* cast_to_friendly() = 0
    virtual const friendly* cast_to_friendly() const = 0


    // The following helper methods are optional but
    // can make it easier to write streamlined code in
    // calling classes with a little trouble.

    // Hostile and friendly can each implement this to return
    // The appropriate enum member. This would useful for making
    // decision about friendlies and hostiles
    virtual FactionType entity_type() const = 0;

    // These two method delegate storage of the knowledge
    // of hostility or friendliness to the derived classes.
    // These are implemented here as non-virtual functions
    // because they shouldn't need to be overridden, but 
    // could be made virtual at the cost of a pointer
    // indirection and sometimes, but not often a cache miss.
    bool is_friendly() const
    {
        return entity_type() == FactionType_friendly;
    }
    bool is_hostile() const
    {
        return entity_type() == FactionType_hostile;
    }
}

由于各种原因,这种策略是好的和坏的。

<强>优点:

概念上很简单。如果您了解多态性,这很容易理解。

它似乎与您现有的代码相似,表面上与现有代码类似,使迁移更容易。在你的类型中编码敌意和友善是有原因的,这保留了这个原因。

您可以安全地使用static_casts,因为所有的强制转换都存在于它们所使用的类中,因此除非有效,否则通常不会被调用。

您可以返回shared_ptr或其他自定义智能指针而不是原始指针。你可能应该这样做。

这避免了可能完全避免铸造的潜在成本高昂的重构。铸造可以用作工具。

<强>缺点:

概念上很简单。这并没有提供一套强大的词汇表(方法,类和模式)来构建一套用于构建高级类型机制的智能工具。

可能某些东西是敌对的应该是数据成员还是实现为控制实例行为的一系列方法。

有人可能会认为返回的指针会传达所有权并删除它们。

每个调用者必须在使用前检查指针的有效性。或者您可以添加要检查的方法,但是调用者需要在强制转换之前调用方法进行检查。像这样的检查对于班级用户来说是令人惊讶的,并使其更难正确使用。

它是多态密集的。这将困扰那些对多态性感到不舒服的人。即使在今天,也有许多人对多态性感到不舒服。

可以完全避免铸造的重构。铸造是危险的,不是轻易使用​​的工具。