C 中的多态性.在基类上调用继承的方法

Polymorphism in C++. Calling inherited methods on base class

本文关键字:调用 继承 方法 多态性 基类      更新时间:2023-10-16

我正在尝试实现一个简单的文件系统。我有一个基类条目。我有两个从称为文件和目录的条目继承的类。目录包含条目对象列表。我有一种称为目录和文件的称为更改的方法,但没有输入。我希望我可以在输入对象上调用此方法,并且编译器会根据条目是目录还是文件来知道使用哪种方法。有什么方法可以做到这一点?

class Entry{
  public:
    std::chrono::time_point<std::chrono::system_clock> dateCreated;
    std::string fileName;
    Entry(std::string name);
    ~Entry();
};
Directory* Directory::changeDir(Directory* dir, Directory* currentDir){
  currentDir = dir;
  return currentDir;
}
void File::changeDir(Directory* dir, Directory* currentDir){
  std::cout<<"You cannot change directories into a filen";
}
unordered_set<Entry*> s;
s.add(File);
s.add(Directory);
for each in s: each.changeDir(); //pseudo code

不幸的是,它告诉我尚未声明" changeir((方法"。我通常只为入口类制定一种方法,但它说目录在此范围内没有声明(显然,因为目录是派生的条目类(。我觉得我以前在Python中做过这种多态性。在C 中没有办法吗?谢谢。

编辑:集合将指针用于输入对象,而不是实际的输入对象。

edit2:看来虚拟类是解决此特定问题的解决方案。我相信,更好,更健壮的解决方案将是让每个目录包含一组文件和一组目录,而不是两者。

您需要虚拟方法:

struct Entry
{
    virtual void changeDir( )
    {
        std::cout << "Entry" << std::endl;
    }
};
struct File : Entry
{
    virtual void changeDir( ) override
    {
        std::cout << "File" << std::endl;
    }
};
struct Directory : Entry
{
    virtual void changeDir( ) override
    {
        std::cout << "Directory" << std::endl;
    }
};

但是,如果您的收藏是普通的Entry对象,则切片将破坏您的所有艰苦工作:

int main()
{
    std::vector< Entry > entries;
    entries.push_back( File { } );
    entries.push_back( Directory { } );
    entries[ 0 ].changeDir( ); // > Entry
    entries[ 1 ].changeDir( ); // > Entry

为了容纳正确的对象,您必须动态分配它们并存储某种指针:

    std::vector< std::unique_ptr< Entry > > entryPointers;
    entryPointers.push_back( std::make_unique< File >( ) );
    entryPointers.push_back( std::make_unique< Directory >( ) );
    entryPointers[ 0 ]->changeDir( ); // > File 
    entryPointers[ 1 ]->changeDir( ); // > Directory
}

一些要点:

  • 在覆盖时不要忘记override指定符 - 这将确保您确实覆盖了基类方法,而不仅仅是声明新方法;
  • 您可能使用原始指针而不是unique_ptr,但这是高度建议的,因为您必须自己释放它们以避免记忆泄漏;
  • 尽管这有效,但建议在可能的情况下避免在接口中使用虚拟方法。例如,请参见此基本草药萨特(Sutter(的文章。

您可以使方法changedir成为纯虚拟函数,然后您可以通过实例化基类对象的指针或参考来实现所需的行为(该指向文件或目录(然后调用该功能,通过多态性,它将被正确调用。[对象切片]

只要您仅参考指针或对目录的引用,就可以将其转发:

class Directory;
class Entry {
  ...
  virtual Directory* changeDir(Directory* dir, Directory* currentDir) = 0;
};

我认为,如果您想在整个集合上调用更改,则应确保所有元素都是目录的实例(因为这仅对它们有意义(,并声明设置为包含目录,而不是条目。

另一方面