Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;纯虚函数继承_C++_Inheritance - Fatal编程技术网

C++ C++;纯虚函数继承

C++ C++;纯虚函数继承,c++,inheritance,C++,Inheritance,我试图创建一个用作基本对象的类,然后将其子类(=实现)以满足各种目的 我想定义一个或多个纯虚函数,这样无论基类如何子类化,都是必需的,并且不会忘记实现它们 有一个警告,纯虚函数的签名包括基对象的类型。一旦子类化,函数定义当然不再与基类定义匹配。例如: class BaseItem { public: virtual std::string getDifferences(const BaseItem& item) = 0; } 因此,在派生类中,我想做: class Deriv

我试图创建一个用作基本对象的类,然后将其子类(=实现)以满足各种目的

我想定义一个或多个纯虚函数,这样无论基类如何子类化,都是必需的,并且不会忘记实现它们

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

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
,但是我不能使用派生类中的任何对象

我必须使用铸造来完成这一点吗


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

实现这一点的一种方法是使用模板,并将参数设置为派生类型的类型

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
  }
};
模板
类基本项{
公众:
虚拟标准::字符串getDifferences(const T&item)=0;
};
类DerivedClass:公共基本项{
公众:
虚拟标准::字符串getDifferences(const-DerivedClass和item){
//在这里实施
}
};

您应该使用cast-from-BaseItem-to-DerivedClass+运行时检查给定的BaseItem是否是DerivedClass实例。

不清楚您想要实现什么。假设编译器允许您这样做(或者通过强制转换的方式),那么它将在类型系统中打开以下漏洞:

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;
};
模板
类DerivedHelper:PublicBaseItem{
公众:
虚拟标准::字符串getDifferences(常量BaseItem和item){
getDifferences(动态施法(项目));
}
虚拟标准::字符串getDifferences(const T&item)=0;
}; 
类DerivedClass:公共DerivedHelper
{
公众:
//不需要更多,但提供它将隐藏getDifferences(const BaseItem&item)
//帮助静态捕获某些使用错误参数类型的情况。
虚拟标准::字符串getDifferences(const-DerivedClass&item)=0;
私人:
std::string-derivedItemCustomObject;
};

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

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

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

如果您担心有时可能会将任何其他派生类对象作为参数传递给该方法,那么请改用
dynamic\u cast
,并在该转换失败时抛出异常。

是的,通常的做法是将参数设为BaseItem,并可能根据派生类中的需要对其进行转换,使用动态_cast@ybungalobill@BoPersson@muntoo:如果不应从基类的接口调用方法,则该方法不应存在于基类的接口中。如果Base::getDifferences的唯一原因是“别忘了实现”,那么Base::getDifferences就不应该存在。@muntoo:您从一个150多个单词的问题中删除了一个(!)单词,并通过一些例子来支持它,人们一致认为可以从一个40个单词的问题中删除30个不必要的单词。。。??更不用说这个词不是问候语,而是一个单独的“谢谢”。顺便说一句,这可能是我第一次发现一个具有不同签名的函数的成员隐藏成员函数的用法。在一开始喜欢它之后,我不确定该隐藏什么。可能有用,但我很谨慎。struct silly示例{BaseItem&x;模板void operator()(T&n){n.getDifferences(x);}}};//你想防止这种情况发生吗?@Fred,我有时不确定我是否需要静态输入:-)在表现力和安全性之间总是有相同的权衡。这不是一个真正的设计,我希望这里的答案能帮助我想出一个好的设计。这似乎是实现我所寻找的最简单的方法,谢谢!谢谢你@iammilind,你让我开心了:)@Eric,很高兴听到。。。这很有帮助。但是,请确保将正确的类型对象传递给函数。
BaseItem *p = new DerivedClass;
DerivedClass obj;
p->getDifferences(obj);  // this always invoke DerivedClass::getDifferences