C++ 将继承对象强制转换为正确子类的最佳实践

C++ 将继承对象强制转换为正确子类的最佳实践,c++,inheritance,C++,Inheritance,我有两个班,每个班都有几个孩子: class ContainerGeneral {...}; class ContainerTypeA : ContainerGeneral { public: void doSomethingA(); }; class ContainerTypeB : ContainerGeneral { void doSomethingB(); }; 解释器类用于对应类型a到a、B到B、General到General的容器。为此,我添加了一个解释器gener

我有两个班,每个班都有几个孩子:

class ContainerGeneral {...};
class ContainerTypeA : ContainerGeneral {
public:
    void doSomethingA();
};
class ContainerTypeB : ContainerGeneral {
    void doSomethingB();
};
解释器类用于对应类型a到a、B到B、General到General的容器。为此,我添加了一个解释器general和一个指向ContainerGeneral对象的成员指针。我希望解释器General将此对象作为ContainerGeneral进行寻址,但我希望继承的类能够将相同的容器作为适当类型的容器进行寻址。我可以通过在寻址继承类时将指针强制转换为继承类来实现这一点示例仅用于节省空间:

(ContainerTypeA*)container->doSomethingA();
或者添加继承类型的新成员指针,该指针将指向与容器相同的位置:

class InterpreterTypeA : InterpreterGeneral {
public:
    void saveContainer(ContainerTypeA* cont) {
        containerA = cont;
        container = cont;
    }
    void doSomething() {
        containerA->doSomethingA();
    }
private:
    ContainerTypeA* containerA;
};

这种情况下的最佳实践是什么?有没有一种方法可以尽可能干净地执行此操作,而无需每次强制转换,也无需添加不包含任何新信息的新成员?

如果您需要有关解释器TypeA和解释器TypeB中容器实例的具体类型信息,通过在GeneralInterpreter中不存储GeneralContainer*数据成员来表达这一点,受保护的数据成员在任何情况下都是很有争议的,而是在子类ExplorerTypeA和ExplorerTypeB中存储具体的ContainerTypeA*和ContainerTypeB*数据成员。存储基类指针,然后通过强制转换绕过其限制,隐藏了需要具体类型信息的事实

此外,在容器基类中提供doSomethingA和doSomethingB的空默认实现,或者将它们转换为虚拟纯成员函数并将空实现转换为ContainerTypeA和ContainerTypeB,也没有什么错。然后,就可以安全地给他们打电话了——如果是不需要的混凝土类型,他们什么也不会做


最后一个迂腐的旁注:我不认为有任何理由调用层次结构中的派生类。常用的术语是子类。

您正在处理的问题有一个解决方案,其形式为。试试这个:

class ContainerGeneral {
public:
    virtual void doSomething() = 0;
};

class ContainerTypeA : public ContainerGeneral {
public:
    void doSomething() {
        std::cout << "Hello A!" << std::endl;
    };
};

class ContainerTypeB : public ContainerGeneral {
public:
    void doSomething() {
        std::cout << "Hello B!" << std::endl;
    };
};

旁注:这当然会产生一些运行时开销。如果在运行时不需要多态性,可以避免这种情况。看一看。只有当你是一个忍者。

是的,在ContainerGeneral中创建一个虚拟doSomething,而不必费心从解释器General继承。这个答案的问题是,它假设doSomethingA和doSomethingB有一些共同点,而事实上,它们根本没有任何共同点。如果我能有一个名字对所有孩子都有意义的函数,我会使用它,但这里没有。你可以假设这些容器是动物,其中一个是鸟,另一个是狗,doSomethingA是layAnEgg,doSomethingB是goforawall。创建一个通用函数名意味着该名称没有意义,并且会创建一个不可读的代码。@SIMEL您必须重新设计。你说他们是不相关的,但似乎你想在口译课上对他们一视同仁。它们是相关的,它们都是同一类型的,并且有很多共享的功能。只是不同的部分非常不同,它们是二进制文件,以不同的格式表示相同的初始数据。因此,最终用户具有相同的接口,并且一些二进制数据是相同的。但是有些数据是完全不同的,不仅相同的数据以不同的方式写入,而且每种格式都有其他格式没有的数据。@SIMEL所以基本上每个类都是一个解析器,是吗?对于接受流并返回公共结构对象的虚拟函数来说,这听起来是一个完美的例子。我鼓励使用它。我接受这个答案是因为第二部分,为B创建doSomethingA的空实现,反之亦然。我需要一个指向父类中容器的指针,因为它使用该类的公共函数,所以第一部分不适用于这里。
class ContainerGeneral {
public:
    virtual void doSomething() = 0;
};

class ContainerTypeA : public ContainerGeneral {
public:
    void doSomething() {
        std::cout << "Hello A!" << std::endl;
    };
};

class ContainerTypeB : public ContainerGeneral {
public:
    void doSomething() {
        std::cout << "Hello B!" << std::endl;
    };
};
class InterpreterGeneral {
public:
    void doSomething()
    {
        container->doSomething();
    }
private:
    ContainerGeneral* container;
};