Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.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++_Overriding_Virtual Functions - Fatal编程技术网

C++ 强制派生类重写至少一个虚拟函数

C++ 强制派生类重写至少一个虚拟函数,c++,overriding,virtual-functions,C++,Overriding,Virtual Functions,想象一下这个简单的基类: struct simple_http_service { virtual reply http_get(…); virtual reply http_post(…); virtual reply http_delete(…); // etc. }; 我想阻止用户在不重写其中至少一个类的情况下从此类派生,并阻止他们实例化simple\u http\u服务 有什么好办法吗?如果您知道希望派生类重写哪些方法,只需声明该方法即可 例如,要使http_获得纯虚拟

想象一下这个简单的基类:

struct simple_http_service
{
  virtual reply http_get(…);
  virtual reply http_post(…);
  virtual reply http_delete(…);
  // etc.
};
我想阻止用户在不重写其中至少一个类的情况下从此类派生,并阻止他们实例化
simple\u http\u服务


有什么好办法吗?

如果您知道希望派生类重写哪些方法,只需声明该方法即可

例如,要使http_获得纯虚拟:

struct simple_http_service
{
  virtual reply http_get(…) = 0;
  virtual reply http_post(…);
  virtual reply http_delete(…);
  // etc.
};

这听起来是一个非常奇怪的限制。尽一切办法保护用户不被错误使用,但不要试图禁止那些你只是“看不到重点”的东西。如果不重写这三个函数中的任何一个就从类中派生没有意义,那么让用户重写任意多或任意少的函数,并相信他不会在不重写任何函数的情况下进行无意义的派生。用户这样做没有坏处,只是没有多大用处

但是,如果您确实需要强制执行这一点(我建议您重新考虑),那么就不要使用虚拟函数。相反,传递函数指针或函数对象(或
std::function
/
boost::function
)回调。使基类看起来像这样:

struct simple_http_service
{
  typedef std::function<reply (...)> func_type;
  reply http_get(...) { return get_func(...); }
  reply http_post(...) { return post_func(...); }
  reply http_delete(...) { return delete_func(...); }
  // etc.

private:
  func_type get_func;
  func_type post_func;
  func_type delete_func;
};
struct simple\u http\u服务
{
typedef std::函数函数函数类型;
回复http_get(…){return get_func(…);}
回复http_post(…){return post_func(…);}
回复http_delete(…){返回delete_func(…);}
//等等。
私人:
func_类型get_func;
func_类型post_func;
func_类型delete_func;
};

现在只需添加必要的构造函数(或自由/静态函数,以便您可以命名它们以避免歧义),这样该类只能在至少提供一个函数对象时实例化。

我认为所有这些函数都应该是纯虚拟的。您发布的结构实际上是一个接口。如果函数不是全部必需的,则派生结构应仅为与它们无关的函数提供空实现。

如果您只是想强制基类为抽象类,请为其提供一个纯虚拟析构函数,我不太明白为什么要为其他两个函数提供默认实现,但在http请求的情况下至少要求其中一个函数是用户定义的。 很明显,如果所有函数都在使用现有代码相互使用来实现某些功能。 想象一下这个类的例子:

Cls类
{
公众:
虚拟std::string toString()=0;
虚拟std::string serialize()=0;
};
存在一个字符串可转换且字符串可序列化的类。但如果其中一个未实现,则您希望调用第二个,因此这将是一个选项:

Cls类
{
公众:
virtual std::string toString()//默认情况下调用serialize()
{
返回此->序列化();
}
virtual std::string serialize()//调用toString()
{
返回此->toString();
}
virtual~Cls()=0;//强制类为抽象类
};  Cls::~Cls(){}
但现在存在从Cls派生但不重写至少一个函数的问题。如果没有进行重写,则在运行时只需输入无限递归。如果这是您的问题之一,那么有一个运行时解决方案,如果出现这样的问题,下面的代码就是什么都不做

Cls类
{
公众:
虚拟std::string toString()
{
if((void*)(this->*(&Cls::serialize))!=(void*)(&Cls::serialize))
{//检查当前实现是否与默认实现不相等
返回此->序列化();
}
其他的
{
return“”;//默认返回值
}
}
虚拟std::字符串序列化()
{
if((void*)(this->*(&Cls::toString))!=(void*)(&Cls::toString)))
{
返回此->toString();
}
其他的
{
返回“”;
}
}
virtual~Cls()=0;
};  Cls::~Cls(){}
这会在GCC上编译,但会在屏幕上显示从funcptr到void*的奇怪转换警告。至少它能按预期工作。可能有一些元编程编译时解决方案,需要考虑一下

附录1,成员函数之间的测试比较:

真的很奇怪

#包括
阶级基础
{
公众:
虚拟int测试()
{
//默认imp
返回0;
}
};
类别:公共基地
{
公众:
int test()重写
{
//海关小鬼
返回1;
}
};
int main()
{
德拉;
碱基b;

std::我能不能90%确定没有一种很好的方法来实现这一点,特别是很难表达约束,比如在C++中执行其中一个,看起来像是不可靠的设计。如果他们可以忽略三个函数中的两个,还有一个呢?如果你提供了所有这些函数的良好默认实现,为什么这不重要o如果有人想要派生出一个使用了所有函数的类?听起来还是很糟糕的设计。让我问一下:如果忽略了其他两个函数,它们的实现是什么?类的用户如何知道哪个函数实际上被重写了?我可以想出一个很好的理由来实例化这个类或派生类that不会覆盖任何函数:测试所有函数在未被覆盖时的行为是否正确。为什么要让这变得更困难?这正是我的问题–我不知道哪一个将被覆盖,但我想强制覆盖至少一个。@Karl:“但我想强制覆盖至少一个”为什么?@GMan因为我不希望可以实例化基类。我想我会编辑这个问题…@karlvonmoor:将其抽象化会阻止它被实例化,但可能无法与您的设计一起使用。“我不希望它成为可能。”