简体   繁体   English

使用纯虚函数的C ++继承

[英]C++ Inheritance with pure virtual functions

I'm trying to create a class that serves as a base object, which will then be sub-classed (=implemented) to serve various purposes. 我正在尝试创建一个充当基础对象的类,然后将其细分(=实现)以用于各种目的。

I want to define one or more pure virtual functions, so that however subclasses the base class, is required and does not forget to implement them. 我想定义一个或多个纯虚函数,因此无论如何都是基类​​的子类,并且不会忘记实现它们。

There is one caveat, the pure virtual function's signature includes the type of the base object. 有一点需要注意,纯虚函数的签名包括基础对象的类型。 Once sub-classed, the function definition doesn't match the base classes definition anymore of course. 一旦被分类,函数定义当然不再与基类定义匹配。 Eg: 例如:

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

So, in the derived class I'd like to do: 所以,在我想做的派生类中:

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

which of course the compiler won't accept. 当然编译器不会接受。 I could make it a BaseItem of course, but then I can't utilize any objects in the derived class. 我当然可以把它变成一个BaseItem ,但是我不能在派生类中使用任何对象。

Do I have to use casting to accomplish this? 我是否必须使用铸造才能完成此任务?

Please let me know if my intent/question is not clear. 如果我的意图/问题不明确,请告诉我。

There is NO need to change the function signature . 无需更改功能签名 Look at following: 请看以下内容:

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);
    }
};

Can use static_cast<> without any fear because, DerivedClass::getDifferences() is called only for DerivedClass object. 可以毫不畏惧地使用static_cast<> ,因为DerivedClass::getDifferences()仅针对DerivedClass对象调用。 To illustrate, 为了显示,

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

If you worry that sometime you might end up passing any other derived class object as an argument to the method, then use dynamic_cast<> instead and throw exception if that casting fails. 如果您担心有时可能会将任何其他派生类对象作为参数传递给该方法,那么请使用dynamic_cast<>并在该转换失败时抛出异常。

It's unclear what you're trying to achieve. 目前还不清楚你想要实现的目标。 Suppose that the compiler allowed you to do this (or you do this by the means of a cast), then it would open the following hole in the type system: 假设编译器允许您执行此操作(或者通过强制转换方式执行此操作),那么它将在类型系统中打开以下漏洞:

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());
}

Your design is probably wrong. 你的设计可能是错的。

I assume that the compiler accept but DerivedClass::getDifferences doesn't override BaseItem::getDifferences. 我假设编译器接受但DerivedClass :: getDifferences不会覆盖BaseItem :: getDifferences。 Here is a way to achieve what you apparently want 这是一种实现您显然想要的方法

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;
};

but be aware that there is a runtime check which will throw exceptions if the argument isn't of the correct class. 但要注意有一个运行时检查,如果参数不是正确的类,它将抛出异常。

One way to accomplish this is to use a template and have the parameter be the type of the derived type 实现此目的的一种方法是使用模板并使参数成为派生类型的类型

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 +运行时检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM