有什么方法可以知道非pure虚拟函数是否已由c 中的派生类实现

Is there any way to know if the non-pure virtual function has been implemented by the derived class in C++?

本文关键字:是否 实现 派生 函数 虚拟 方法 什么 pure      更新时间:2023-10-16

我正在创建一个基于回调的类。我需要给客户一个自由来调用他定义的回调。例如,我有一个班级基础:

class Base
{
...
 public:
    virtual void OnMsgReceived(const char *msg, char *&response);
    virtual void OnMsgReceived(const char *msg, string &response);
};

客户端必须实施任何一个,而不是2。我怎么知道他已经实施了哪一个因此,当我处理回调时,我打电话给正确的一个?

我知道我在对象的构造实例化过程中无法执行此操作,但是一旦对象实例化,我是否有任何办法检查这些虚拟功能中的哪一种已实现?谢谢。

在没有纯virtual技术的C 中,在运行时无法知道是否通过类实现virtual函数。

将两个函数定义为纯虚拟函数,并让客户端实现两个函数。如果需要,您仍然可以具有Base的纯虚拟功能。

客户必须实现任何一个,但不能实现2。

假设两个版本都是真正需要的,我不需要上述要求。

我怎么知道他已经实施了哪一个,以便当我处理时 回调,我叫正确的一个?

将适当的对象分配给Base参考/指针后,您就不必担心这一点。编译器为您完成了肮脏的工作。

在旁注,您还可以探索CRTP技术。如果派生类必须实现给定方法以传递汇编。但是,这不会像virtual功能那样灵活。

我想向iammilind的响应添加一些东西:

如果您在类中使用纯虚拟函数,则您正在制作该类别的抽象,因此您无法实例化。

如果A是抽象类

class A
{
  public:
  //
  virtual void foo() = 0;
  //
}

你不能写

A myA

与往常一样,一个很好的资源是Parashift C FAQ网站。

荒谬的方法:在基类中从一个到另一个派遣。除非用户至少覆盖其中一个会导致堆栈流,否则很容易被检测到:

void Base::OnMsgCallback(const char *msg, char*& response) {
   std::string resp;
   OnMsgCallback(msg,resp);
   response = new char[resp.size()+1]();
   std::copy(resp.begin(), resp.end(), response);
}
void Base::OnMsgCallback(const char *msg, std::string& response) {
   char *resp;
   OnMsgCallback(msg,resp);
   response = resp;
   delete [] resp;
}

但这是一个可怕的黑客,您可能已经注意到char*版本需要手动处理资源,这是错误的。通过定义将引用到std::string的单个接口(或具有std::string的返回类型,它可以简化合同(IS response AN Inout 或Just out 数?)和代码(在调用回调之前,不需要创建std::string

弄清楚哪个功能已被覆盖并不容易 - 即使可以,它也是一个很难遵循的设计:客户端必须实现一个但不是2 - 开发人员可能会忘记它,他们可能不喜欢它!

我建议一种基于您设计的替代方法:

您的框架

class Base0
{
public:
    // other basic members
};
template<class T>
class Base : public Base0
{
    virtual void OnMsgReceived(const char *msg, T &response) = 0;
};

typedef Base<char*> BaseChar;
typedef Base<string&> BaseString;

void run(Base0* pBase)
{
    const char* msg = getmsg();
    BaseChar* p = dynamic_cast<BaseChar*>(pBase);
    if(p != NULL)
    {
        char* response; // 
        p->OnMsgReceived(msg, response)
        return;
    }
    BaseString* p2 = dynamic_cast<BaseString*>(pBase);
    if(p2 != NULL)
    {
        string response; // 
        p2->OnMsgReceived(msg, response)
        return;
    }
}

客户端代码

class Derived: public BaseChar
{
public:
    virtual void OnMsgReceived(const char *msg, char* &response)
    {
        // do sth
    }       
};

您的框架用户需要实现Basechar或固定,然后一切都起作用。

,由于许多原因,设计是有害的,无论如何,有一种方法可以做到:

class Base
{
public:
    virtual void OnMsgReceived(const char *msg, char *&response)
    {
        response = (char*)"OMG! nothing derived"; // or throw if you want
    }
    virtual void OnMsgReceived(const char *msg, string &response)
    {
        char *ptr_to_dest = 0;
        OnMsgReceived(msg, ptr_to_dest);
        response = ptr_to_dest;
    }
};

you 始终使用 string 调用,您不需要检查他们做了哪一个。

这将取决于其实施的情况:

  • 仅实现 char 版本 ->它将被调用并转换为字符串
  • 仅实现 String 版本 ->它将直接称为
  • 无需任何实施 ->您将获取默认消息(如果投掷(如果您扔)例外)