C++ 继承类的意外转换
我想做一种“收藏”。此类需要接受从基类继承的所有类 例如: 想象一下,我们有一个名为“a”的基类,我们还有许多从这个类“a”继承的其他类。所以我们有,从“A”继承的类“B”,从“A”继承的类“C”,等等,我们还有一个从“A”继承的名为“collection”的类。类“collection”有一个“std::map”,其中使用“add”方法保存所有类,并可以使用“get”检索这些类 实际情况是,它以某种方式工作,但应用程序将转换为“基类”,而不是返回传递的类 让我们转到代码(请参阅代码上的注释以了解输出): 这是工作代码:C++ 继承类的意外转换,c++,inheritance,C++,Inheritance,我想做一种“收藏”。此类需要接受从基类继承的所有类 例如: 想象一下,我们有一个名为“a”的基类,我们还有许多从这个类“a”继承的其他类。所以我们有,从“A”继承的类“B”,从“A”继承的类“C”,等等,我们还有一个从“A”继承的名为“collection”的类。类“collection”有一个“std::map”,其中使用“add”方法保存所有类,并可以使用“get”检索这些类 实际情况是,它以某种方式工作,但应用程序将转换为“基类”,而不是返回传递的类 让我们转到代码(请参阅代码上的注释以了
#include <iostream>
#include <string>
#include <map>
class A
{
public:
virtual void saySomething()
{
std::cout << "Hello from A object" << std::endl;
}
};
class B : public A
{
public:
void saySomething()
{
std::cout << "Hello from B object" << std::endl;
}
};
class C : public A
{
void saySomething()
{
std::cout << "Hello from C object" << std::endl;
}
};
class Collection : public A
{
public:
void add(const std::string & key, A * value)
{
storage[key] = value;
}
A * get(const std::string & key)
{
return storage[key];
}
private:
std::map<std::string, A *> storage;
};
int main( int argc, char ** argv )
{
B * b = new B;
C * c = new C;
Collection * col = new Collection;
Collection * col2 = new Collection;
col->add("b", b); // works, because "b" inherits from "A" class.
col->add("c", c); // works, because "c" inherits from "A" class.
col->add("col2", col2); // watch this part...
col->get("b")->saySomething(); // works - Output: Hello from B object
col->get("c")->saySomething(); // works - Output: Hello from C object
return 0;
}
如果我没有错,它需要工作,因为“get”方法返回对象,所以我有“col2”对象的方法,对吗?如果你回答是的,我们有相同的想法,我不知道发生了什么。在“b”和“c”对象上,它返回对象,我有“saySomething”方法,但当我尝试检索“col2”时,它将对象作为“A”对象,因此错误:
“class A”没有名为“add”的成员
如果我这样做,情况会变得更糟:
col->get("col2")->saySomething(); // output: Hello from A object
其思想是,一个集合只接受从基类继承的类,也接受从同一基类继承的其他集合,如递归,因此,当您有一个类型为
A
的对象时,这就是get
方法返回的结果-只能使用A
中声明的方法。要对get
的结果调用add
,您需要使用static\u cast
或dynamic\u cast
进行强制转换,或者重新考虑您的类层次结构。为什么Collection
需要从A
继承?(为了回答您的最后一个问题,因为它继承了,如果您调用saySomething
,它将调用A
中声明的方法,因为集合
不提供它自己的覆盖)。您感到惊讶吗?您的get
调用返回一个A*
,并且A*
是否有一个add()
方法?此外,您的集合
类继承自A
,但不重写方法saySomething()
,因此您为什么对输出感到惊讶?不要使用公共继承,除非继承的类是父类的“A”Collection
不是a
,因此从a
公开继承它是一种糟糕的设计。如果你想访问不属于a
接口的方法,你需要强制转换到Collection
。@Nim-你说的没有意义,因为我知道a没有实现方法“get”但重要的是,从A继承的“集合”具有该方法。@Tilart-你能给我解释一下吗?“其思想是,一个集合只接受从基类继承的类,也接受从同一基类继承的其他集合,比如递归。”-这就是为什么该系列也从A继承的原因。-你有没有关于我如何在这种情况下实施“静态”或“动态”的例子我会看到更多关于这一点,谢谢。我为你看到以下选项:1。强制转换,例如动态强制转换(col->get(“col2”)->add(“b”,b);(您应该测试强制转换是否返回NOTNULL)2。将集合方法添加到基类3。使用访问者设计模式。我认为1是最糟糕的——石膏是危险的并发症,通常是设计错误的信号。您可以考虑将集合方法添加到<代码> A<代码>中,并在<代码> A/<代码>实现中抛出异常,而在<代码>集合中重写应该做什么。我喜欢您的答案。我在互联网上看到一些帖子,说演员阵容也是这样,很危险等等。关于在上添加集合方法我尝试了,但出现了错误。我认为您只添加了声明,而没有大括号中的函数体。我按照您所说的做了,首先我只做了声明,而没有函数体,以查看会发生什么,因为集合有方法,所以它可能会重写,但不起作用,所以我用大括号表示身体,它起作用了。但我认为这很奇怪。我是说类“A”就是“一切”,想象一下如果我有更多的类,我需要在A上声明所有的类?我要A类是一种类型,就是这样。有一种方法不需要声明类a上的所有方法就可以实现吗?非常感谢。
col->get("col2")->saySomething(); // output: Hello from A object