我是C ++的新手。我有两个纯抽象类(如接口),我从这两个纯抽象类派生了一个类。
在一种情况下,我需要将派生类的指针上移到基本抽象类之一。首先,对此有任何限制。
class IBase1
{
virtual ~IBase() = default;
}
class IBase2
{
virtual ~IBase2() = default;
}
class Derived : public IBase, public IBase2
{
}
Derived d;
IBase1* basePtr = dynamic_cast<IBase1*>(&d);
这里,如果我使用任何其他强制类型转换,我不太确定,但是我从强制类型转换中获得了无效的指针,所以我需要使用dynamic_cast从多个继承进行向上转换,对吗?
当我这样做时,出现错误“源类型不是多态的”
我的基类是纯抽象类,因此它们至少具有一个虚拟方法,应该可以,对,但是为什么我会收到此错误?关于多重继承吗?
编辑:这里还有一层。我的派生类需要包含两种不同类型的实例,但是我的实例确实是一个巨大的变量,因此作为C开发人员:),我计划使用Union来减少内存使用量。联合仅具有从纯抽象类派生的两个类的实例。因此,我以为联合实例地址也应指向类实例的偏移量,但是C ++可能无法知道写成员方法的地址。
class IFile
{
public:
virtual ~IFile() = default;
};
class IDirectory
{
public:
virtual ~IDirectory() = default;
};
class FileSystem1 : public IFile, public IDirectory
{
public:
FileSystem1() { }
virtual ~FileSystem1() final override = default;
private:
Native1APIInstance file;
};
class FileSystem2 : public IFile, public IDirectory
{
public:
FileSystem2() { }
virtual ~FileSystem2() final override = default;
private:
Native2APIInstance file;
};
union FileSystemInstance
{
FileSystem1 fs1;
FileSystem2 fs2;
FileSystemInstance(string path)
{
if (path[0] == '1') // initialise fs1
else if (path[0] == '2') // initialise fs2
}
};
FileSystem fs("<PATH to File System>");
IFile* file = reinterpret_cast<IFile*>(&fs);
这里,我不想对初始化哪个实例感兴趣。我只想使用基类接口。我想知道联盟是否有可能?
谢谢。
class FileSystem1 : public IFile, public IDirectory
让我们坐下来,想一会儿。这断言了FileSystem1
is(或更正式地,在任何可能的情况下,都可以代替IFile
或IDirectory
。)>
至少在大多数人使用这些术语时,根本不是这样。正如大多数人使用的术语一样,文件系统contains
某些东西,每个东西都可以是文件或目录:class FS_node { virtual std::string name() const { return name_; } // ... virtual ~FS_node = default; }; class File : public FS_node { // ... }; class Directory : public FS_node { // ... }; class FileSystem { std::vector<FS_node *> nodes; public: // ... };
现在,从事态发展来看,您必须处理两个完全独立的文件系统。有很多方法可以做到这一点。一种可能性是拥有一个FileSystem基类,该基类定义了文件系统的接口,然后具有两个派生类,这些派生类根据操作系统级别的两个独立API来实现该接口。
另一种可能性是实现类似的功能,但是在实例化FileSystem
对象时,您可以将API接口类指定为模板参数,而不是使用继承:
template <class Api> class FileSystem { Api api; public: FileSystem(Api const &api) : api(api) {} // FS functions for finding files and such go here, // each implemented via the `Api` passed as a parameter };
关于使用模板和继承之间的区别:与通常的用法几乎相同:模板是静态的,因此,例如,如果您想要在编译时可以指定是针对Windows还是Linux进行编译的代码,则模板应做得好。另一方面,如果要处理的是单个文件系统集合,并且该集合可能包含对象的混合物,则每个对象代表一个不同的文件系统,并且您希望能够透明地处理所有这些对象在运行时,那么您可能需要使用继承层次结构。
但是至少对我来说,您从FileSystem
和File
类派生的Directory
原始设计似乎很可能是一个非常严重的错误。我们可能需要更多地了解您在做什么,以确保哪种方法真正是最佳的,但是事实并非如此。
暂时忽略所有有关设计的内容,并考虑如何从指针到派生转换为指向基的问题,我们实际上只有两种情况非常重要。如果您使用公共继承(如问题所示),则该转换完全不需要强制转换:
FileSystem1 foo1; IFile *fileBase = &foo1; // No problem. IDirectory *dirBase = &foo1; // Likewise
如果使用私有派生,那么您刚刚发现了一种极为罕见的情况:您实际上需要使用C样式强制转换正确地进行转换:
我们使用C风格的强制转换。class Base1 {}; class Base2 {}; // Note: private derivation: class Derived : Base1, Base2 {}; Derived d; Base1 *b1 = (Base1 *)&d; Base2 *b2 = (Base2 *)&d;
对于这种特定情况(将派生类转换为不可访问的基类),任何“新” C ++强制类型转换都不能胜任—您必须