C++ 具有纯虚函数的继承

C++ Inheritance with pure virtual functions

本文关键字:函数 继承 C++      更新时间:2023-10-16

>我正在尝试创建一个用作基本对象的类,然后将其子类化(=实现)以服务于各种目的。

我想定义一个或多个纯虚函数,以便无论基类的子类是什么,都是必需的,并且不要忘记实现它们。

有一个警告,纯虚函数的签名包括基本对象的类型。一旦子类化,函数定义当然不再与基类定义匹配。例如:

class BaseItem 
{
public:
    virtual std::string getDifferences(const BaseItem& item) = 0;
}

所以,在派生类中,我想做:

class DerivedClass : public BaseItem
{
public:
    virtual std::string getDifferences(const DerivedClass& item) = 0;
private:
    std::string derivedItemCustomObject;
}

编译器当然不会接受。当然,我可以把它变成一个BaseItem,但是我不能利用派生类中的任何对象。

我必须使用铸造才能完成此操作吗?

如果我的意图/问题不清楚,请告诉我。

无需更改函数签名。请看以下内容:

class BaseItem 
{public:
    virtual std::string getDifferences(const BaseItem& item) = 0;
};
class DerivedClass : public BaseItem
{public:
    virtual std::string getDifferences(const BaseItem& item)  // keep it as it's
    {
       const DerivedClass& derivedItem = static_cast<const DerivedClass&>(item);
    }
};

可以毫无畏惧地使用static_cast<>,因为DerivedClass::getDifferences()只为DerivedClass对象调用。为了说明,

BaseItem *p = new DerivedClass;
DerivedClass obj;
p->getDifferences(obj);  // this always invoke DerivedClass::getDifferences

如果您担心有时最终可能会将任何其他派生类对象作为参数传递给该方法,请改用dynamic_cast<>并在该强制转换失败时引发异常。

目前还不清楚你想实现什么。假设编译器允许您执行此操作(或者通过强制转换执行此操作),那么它将在类型系统中打开以下漏洞:

class BaseItem 
{
public:
    virtual std::string getDifferences(const BaseItem& item) = 0;
};
class DerivedClass : public BaseItem
{
public:
    virtual std::string getDifferences(const DerivedClass& item) 
    {
        item.f(); 
        // ... 
    }
    void f() const {}
};
class DerivedClass2 : public BaseItem
{
public:
    virtual std::string getDifferences(const DerivedClass2& item) { ... }
};
void g()
{
    BaseItem* x = new DerivedClass;
    // oops, calls DerivedClass::f on an instance of DerivedClass2
    x->getDifferences(DerivedClass2());
}

你的设计可能是错误的。

我假设编译器接受,但DerivedClass::getDifferences不会覆盖BaseItem::getDifferences。 这是一种实现您显然想要的方法

template <typename T>
class DerivedHelper: public BaseItem {
public:
   virtual std::string getDifferences(const BaseItem& item) {
      getDifferences(dynamic_cast<const T&>(item));
   }
   virtual std::string getDifferences(const T& item) = 0;
}; 
class DerivedClass : public DerivedHelper<DerivedClass>
{
public:
   // not more needed but providing it will hide getDifferences(const BaseItem& item)
   // helping to statically catch some cases where a bad argument type is used.
   virtual std::string getDifferences(const DerivedClass& item) = 0;
private:
   std::string derivedItemCustomObject;
};

但请注意,如果参数不属于正确的类,则运行时检查将引发异常。

实现此目的的一种方法是使用模板,并使参数成为派生类型的类型

template <typename T>
class BaseItem {
public:
  virtual std::string getDifferences(const T& item) = 0;
};
class DerivedClass : public BaseItem<DerivedClass> {
public:
  virtual std::string getDifferences(const DerivedClass& item) {
    // Implement it here
  }
};

如果给定的 BaseItem 是 DerivedClass 实例,则应使用 BaseItem 到 DerivedClass 的强制转换 + 运行时检查。