简体   繁体   English

有没有办法知道C ++中的派生类是否实现了非纯虚函数?

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

I am creating a class which is callback based. 我正在创建一个基于回调的类。 I need to give the client a freedom to invoke the callback that he defines. 我需要让客户自由地调用他定义的回调。 For example, I have a class Base: 例如,我有一个类Base:

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

The client MUST implement either one, but not 2. How do I know which one he has implemented so that when I handle the callback, I call the right one? 客户端必须实现其中一个,但不能实现2.我如何知道他实现了哪一个,这样当我处理回调时,我会调用正确的回调?

I know I can't do it during the construction instantiation of the object, but once the object is instantiated, is there any way for me check which one of these virtual functions has been implemented? 我知道在对象的构造实例化期间我不能这样做,但是一旦对象被实例化,有没有办法让我检查这些虚拟函数中的哪一个已经实现了? Thanks. 谢谢。

In C++ without pure virtual technique, there is no way to know at runtime if a virtual function is implemented or not by a class. 在没有纯virtual技术的C ++中,没有办法在运行时知道类是否实现了virtual函数。

Define both the functions as pure virtual functions and let the client implement both of them. 将这两个函数定义为纯虚函数,并让客户端实现它们。 You still can have body of pure virtual function for Base if needed. 如果需要,你仍然可以为Base提供纯虚函数体。

The client MUST implement either one, but not 2. 客户端必须实现一个,但不能实现2。

Assuming that both versions are genuinely needed, I don't feel a need of having the above requirement. 假设两个版本都是真正需要的,我觉得不需要满足上述要求。

How do I know which one he has implemented so that when I handle the callback, I call the right one? 我怎么知道他实施了哪一个,这样当我处理回调时,我会拨打正确的回叫?

Once you assign a proper object to a Base reference/pointer, you don't have to worry about this. 将适当的对象分配给Base引用/指针后,您不必担心这一点。 Compiler does that dirty job for you. 编译器为你做了那份肮脏的工作。

On side note, you can also explore CRTP technique. 另外,您还可以探索CRTP技术。 Where a derived class must implement a given method to pass the compilation. 派生类必须实现给定方法来传递编译。 However that won't be as flexible as the virtual functionality. 但是,这不会像virtual功能那样灵活。

I would like to add something to the iammilind's response : 我想在iammilind的回复中添加一些内容:

If you use a pure virtual function in a class you are making that class abstract and, as consequence, you can't instanciate it. 如果在类中使用纯虚函数,则会使该类成为抽象类,因此,您无法实现它。

if A is an abstract class 如果A是抽象类

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

you can't write 你不能写

A myA

One good resource about this is, as usual, the Parashift C++ FAQ website . 像往常一样,一个很好的资源就是Parashift C ++ FAQ网站

Absurd approach: dispatch in the base class from one to the other. 荒谬的方法:在基类中从一个派遣到另一个。 Unless the user has overridden at least one of them that will lead to a stackoverflow that is easily detectable : 除非用户已覆盖其中至少一个将导致易于检测到的堆栈溢出

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

But this is a terrible hack, and as you might have noticed the char* version requires manual handling of resources, which is error prone. 但这是一个可怕的黑客,你可能已经注意到char*版本需要手动处理资源,这很容易出错。 You are much better off by defining a single interface that passes a reference to a std::string (or has a return type of std::string , which simplifies the contract (is response an inout or just out parameter?) and the code (no need to create the std::string before calling the callback. 通过定义一个传递对std::string的引用的单个接口(或者返回类型为std::string ,这简化了契约(是一个inout或者只是out参数的response ?)和代码,你会好得多(在调用回调之前无需创建std::string

It is not easy to figure out which function has been overridden - even if you can, it is also a design which is very hard for developers to follow: The client MUST implement either one, but not 2 - developers may forget it, and they may not like it! 要弄清楚哪个函数被覆盖是不容易的 - 即使你可以,它也是一个开发人员很难遵循的设计: 客户端必须实现其中一个而不是2个 - 开发人员可能会忘记它,并且它们是可能不喜欢它!

I would suggest an alternative way based on you design: 我会建议一种基于你设计的替代方法:

Your framework 你的框架

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

}

Client Code 客户代码

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

User of your framework needs to implement either BaseChar, or BaseString, then everything just works. 框架的用户需要实现BaseChar或BaseString,然后一切正常。

That design is bad for so many reasons, anyway there is a way to do your way: 这个设计很糟糕,原因很多,无论如何都有办法按你的方式行事:

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 always call the one using string , you don't need to check which one they did. 总是使用字符串调用一个,你不需要检查他们做了哪一个。

This is what will happen depending on what they implement: 这将根据他们实施的内容发生:

  • Only implement char version -> it will be called and converted to string 只实现char版本 - >它将被调用并转换为字符串
  • Only implement string version -> it will be called directly 只实现字符串版本 - >它将直接调用
  • Implement both versions -> only string will be called 实现两个版本 - >只调用字符串
  • implement nothing -> you will get your default message (or a exception if you throw) 什么都不实现 - >你会得到你的默认信息(如果你抛出则是例外)

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

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