当子类定义新的成员变量时,我可以避免使用dynamic_cast吗?

时间:2015-02-04 19:10:20

标签: c++ c++14

我试图用现代的方式编写应用程序" C ++风格,同时试图学习如何做到这一点,并且已经陷入了一个应该是相当基本的设计问题。

应用程序会索引各种内容,例如文件/文件夹,音乐(通过某些音乐播放器API,而不是文件系统)以及未来的书签等等。
问题在于代表这些事情。我的计划是使用基类,例如IndexedObject,然后我将其子类化为IndexedFileIndexedSong等等。

这些类型的对象需要有一些共同的成员,有些则不需要。所有类型都需要在应用程序中显示一个图标和一个名称,因此这些显然都在IndexedObject。但是,索引文件需要完整路径,而索引歌曲需要艺术家,专辑和标题,但我们可能不知道它的路径(它甚至可能不在磁盘上)。将所有这些存储在一个单独的类中似乎非常难看,在这种情况下,我仍然需要一个"类型"成员来弄清楚特定的类实例应该代表什么。

对于我有IndexedObject但只需要访问IndexedFile等特定子类的信息的程序部分,是否有比使用dynamic_cast更好的选择,或者这是应该使用的时间? 通过"更好",我的意思是任何更好的合理定义,例如具有更高的性能,更安全等等。顺便提一下,其他选项可能包括一个完全不同的设计。这个基类/子类设计是我想到的第一件事。

更新

一些评论者要求提供代码。但是,我并没有太多与此特定问题相关的代码;问题是我应该如何设计和编码(子类方法是否正确)。我可以在我需要的东西上超级具体,但是对于除我之外的任何人来说,答案对于任何人来说都是无用的 不过,我可以提供一些关于目标是什么的额外细节,如果你想要,请继续阅读。

该程序对后台提到的各种内容进行索引,并将它们存储在某种容器类型中(在我的例子中为QVector),以便于检索。用户通过一些热键启动应用程序,并键入搜索术语。对于每个键入的字母,应用程序会过滤索引,并显示匹配项。

对于找到的每个匹配,UI需要知道其类型。如果它是一首歌,也许我们想将其格式化为" 艺术家 - 曲目名称(来自专辑)&# 34;或者其他的东西;如果它是书签,可能会显示域名和URL的一部分,依此类推。

换句话说, if 我使用子类方法,我可能会这样做:

// The real code would of course have a bit more meat with some basic methods

class IndexedObject {
    string name;
    image icon;
};

class IndexedSong : public IndexedObject {
    string artist;
    string title;
};

class IndexedBookmark : public IndexedObject {
    some_url_type url;
};

void displayObject(const IndexedObject &obj) {

    // Pseudo-C++ follows
    if (obj is IndexedSong) {
        display icon, artist and title
    }
    else if (obj is IndexedBookmark) {
        display icon, name and URL;
    }
}

...这个例子的问题是,问题不是如何使用dynamic_cast,上面的例子似乎暗示我必须,但是否有一个完全不同的方式解决这个问题,完全避免了dynamic_cast。

3 个答案:

答案 0 :(得分:3)

对于您的代码,您可以在基类中定义虚函数,并让子类实现该函数,这可以避免dynamic_cast。代码将是这样的:

class IndexedObject {
    string name;
    image icon;
public:
    virtual void display() = 0;
};

class IndexedSong : public IndexedObject {
    string artist;
    string title;
    public:
       virtual void display()
       {/////}
};

class IndexedBookmark : public IndexedObject {
    some_url_type url;
   public:
       virtual void display()
       {/////}
};

void displayObject(const IndexedObject &obj) {

    obj.display()
}

Open-Closed principle是处理这种情况,您可以在网址中找到更多详细信息,并讨论如何不使用dynamic_cast。

答案 1 :(得分:0)

不使用dynamic_cast,首选的方法是将不同类的必须完成的部分放入虚函数中。寻找和了解的术语是多态性"。

P.S。也许根本不使用继承也不是一个好主意 - 可能还有一些歌曲也是文件。组合可能会更好。

答案 2 :(得分:0)

多态数据存储类型对于C ++来说是一个问题,因为良好的OOP风格要求多态行为应该存放在子类本身中......也就是说,IndexedObject将具有纯粹的 - 虚拟play()功能,IndexedSong的实现会播放一首歌,IndexedVideo会播放视频,依此类推。但如果它是其他消耗数据的东西,那么很难为它做一个漂亮的抽象接口。

dynamic_cast,在这种情况下几乎总是使用指定类型的枚举等。