多态性 c++,试图访问从抽象基 class 派生的 classes 的成员函数

polymorphism c++, trying to access member functions of classes that are derived from abstract base class

所以我有 5 个 classes,

  1. CD
  2. DVD
  3. 书籍
  4. 项目
  5. 库存

我的项目 class 是一个抽象基础 class 并且 cd、dvds 和书籍都是从它派生出来的。 我的库存 class 有一个 Items 类型的指针数组,指向 cd、dvd 和书籍的对象。

这是数组:

Item* ptrItems[100];
int totalItems = 0`

以下是如何将对象分配到我的库存中的数组 class:

ptrItems[totalItems++] =  new books(1000 + totalItems, quantity, tempTitle,tempAuthor, tempDesc, cost);

//我使用总项目作为计数器来跟踪索引

我遇到的问题是 ptrItems[totalItems] 无法访问派生的成员函数 classes 只能访问 Items 抽象的成员函数 class。

例如:

ptrItems[i]->getQuantity() //works fine because getQuanty is a member function of abstract base class Item.

然而,

ptrItems[i]->getBookTile() // won't work
error C2039: 'getBookTile' : is not a member of 'Item'  

如果我错了请纠正我,但这不是多态性吗?它应该可以访问派生的 classes public 成员函数,对吗?

您需要先将 Item* 指针转换为 Books* 指针

Books * ptrBooks = dynamic_cast<Books*>(ptrItems[i]);

if(ptrBooks)
{
    ptrBooks->getBookTitle();
}

检查 ptrBooks 的值是否为非零很重要,因为如果指向 Item 的指针传递给 dynamic_cast 没有指向 Books 对象,它将 return 为零。这是一种从基指针测试派生对象类型的方法。

不,你想做的不是多态。它实际上与多态性完全相反。

多态性仅使用 您的基础 class 接口来操纵 任何 派生的 classes,包括还没写的

例如,如果你想让你的项目有标题,你可以在你的基础class中定义一个虚拟(可能是纯的)方法getTitle(),并在派生的 classes 中实现它。通过这种方式,您可以在 collection 中获取任何项目的标题,而无需知道或关心其确切类型。

我强烈建议重新考虑设计。多态性就是以相同的方式处理潜在的不同想法,而您尝试做相反的事情。有很多方法可以做到这一点,例如dynamic_cast,但这通常是糟糕设计的标志,应该避免。

看起来你的对象或多或少是数据对象。作为第一步,尝试将操作分配给对象,而不仅仅是 return 某些成员变量(例如 getBookTile())的方法。然后,将这些服务的公共部分放在基础中class,并使用在公共实现中调用的抽象方法来提供子类型特定的部分。

对于眼前的问题,如果你真的想那样做,一个解决方案是使用 dynamic_cast:

dynamic_cast<books*>(ptrItems[i])->getBookTitle();

您可能还想查看 std::vector 作为 C 样式数组的更好替代品。并用一些智能指针替换普通指针,例如std::shared_ptrstd::unique_ptr,取决于您的所有权关系。

Item 无法知道每个 Item 是否都有方法 getbookTitle(),在这种情况下,很明显它们没有。假设您有一个项目数组,但并非所有项目都是书籍。那么你会 运行 惹上麻烦。由于这种不一致,在 C++ 中不允许这样的方法调用。解决此问题的方法是按照 galinettes 答案中所述进行 dynamic cast。但是,您通常不希望在代码中多次执行此操作。它会变得混乱并需要大量额外的检查(如您所见,在这种情况下是不必要的)。具有大量转换的代码通常是某处设计缺陷的标志。

但是,在这种情况下,我可以假设所有 objects 都会有一个 title。然后可以在基础 class.

中声明一个 virtual 方法
virtual string title() = 0; //Pure virtual

此方法必须在所有派生的 classes 中实现。现在可以在基 class 中看到该方法,并且从该基 class 派生的所有 class 都必须实现该方法。编译器知道该方法是虚拟的,因此将在 class 层次结构中搜索以找到正确的实现。现在可以调用

ptrItems[i] -> title();

可以在

中看到简短的描述

http://www.cplusplus.com/doc/tutorial/polymorphism/

此外,为了简化内存管理和更简洁的代码,除非您有充分的理由,否则最好使用范围检查容器,例如 std::vector