简体   繁体   English

需要有关多重继承和覆盖C ++的可选函数的建议

[英]Need recommendations on multiple inheritance and optional function overriding C++

I've got a problem I'm trying to solve where I'd like to have some abstract base class, that inherits from multiple classes, where derivations can optionally have their methods overridden without declaring an additional class. 我有一个问题正在尝试解决,我想在哪里拥有一些抽象基类,该基类继承自多个类,在这些类中,派生可以有选择地重写其方法而无需声明其他类。 I'll give an example here of what I'm trying to achieve: 在这里,我将举例说明我要实现的目标:

#include <iostream>

using namespace std;

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

    protected:
        A() {}
};

class A1 : public A
{
    public:
        A1() : A() {}

        void foo() { cout << "A1 foo" << endl; };
};

class A2 : public A
{
    public:
        A2() : A() {}

        void foo() { cout << "A2 foo" << endl; };
};

class B
{
    public:
        virtual void bar() { cout << "B bar: " << endl; }
};

class B1 : public B
{
    public:
        void bar()
        {
            cout << "B1 bar wrapper begin" << endl;
            B::bar();
            cout << "B1 bar wrapper end" << endl;
        }
};

/*
  ???
  pure virtual class C
  enforce derived classes to inherit something of type A
  enforce derived classes to inherit something of type B

  class C1 : public A1, either B or B1 ??? templates???
  {

  }

  class C2 : public A2, either B or B1 ??? templates???
  {

  }

  Can this be done without having to define classes CA1B, CA2B, CA1B1, CA2B1, etc.?
*/

int main(int argc, char *argv[])
{
    A1 a1;
    a1.foo();
    A2 a2;
    a2.foo();

/*
    C1 c1b with type B
    C1 c1b1 with type B1
    C2 c2b with type B
    C2 c2b1 with type B1

    put c1b, c1b1, c2b, c2b1 in a list named "combinations"

    cout << "Printing combinations" << endl;
    for (auto i : combinations)
    {
        i->foo();
        i->bar();
    }
*/

    return 0;
}

In theory the output would be: 理论上,输出将是:

A1 foo
A2 foo
Printing combinations
A1 foo
B bar
A1 foo
B1 bar wrapper begin
B bar
B1 bar wrapper end
A2 foo
B bar
A2 foo
B1 bar wrapper begin
B bar
B1 bar wrapper end

If there's a way to accomplish this through some design pattern, or I'm using a bad approach, please let me know. 如果有办法通过某种设计模式来完成此任务,或者我使用的是错误的方法,请告诉我。 I'm using C++11. 我正在使用C ++ 11。

Your use case screams "templates with constraints". 您的用例会尖叫“带有约束的模板”。 What you are missing is how to check and encode that the template parameters inherit from the correct classes. 您缺少的是如何检查和编码模板参数是否从正确的类继承。 You can do that with std::is_base_of 您可以使用std::is_base_of

template<class A_, class B_,
         typename std::enable_if<std::is_base_of<A, A_>::value>, int>::type = 0,
         typename std::enable_if<std::is_base_of<B, B_>::value>, int>::type = 0>
class C : public A_, public B_
{

};

Here's how it works: 运作方式如下:

std::enable_if will have a type (an int as in our case), iff the boolean expression it is fed is true. 如果提供的布尔表达式为true,则std::enable_if将具有type (在我们的情况下为int )。 Otherwise there is no type there, and the template will not compile. 否则,那里没有类型,并且模板将无法编译。 If there is a type there, then we obtained a non-type template parameter, which we give the default value of 0 to. 如果那里有类型,那么我们获得了一个非类型模板参数,我们将其默认值设置为0 Assigning the default is what makes us able to instantiate the template with two arguments. 分配默认值使我们能够使用两个参数实例化模板。

You'll find these utilities, and more, in the <type_traits> header. 您可以在<type_traits>标头中找到这些实用程序以及更多内容。

I was interested in this subject a while back so I have some strategies. 不久前,我对此主题很感兴趣,因此我有一些策略。 I think a socket program is the perfect demonstration of this type of abstraction. 我认为套接字程序是这种抽象类型的完美演示。 One of the easiest things to do is declare a base header with functions and variables you want available in any object of the class you declare. 最简单的操作之一是声明一个基本标头,其中包含要在所声明的类的任何对象中使用的函数和变量。 Then create classes that inherit from the base class when ITSELF is set as the template argument. 然后,在将ITSELF设置为模板参数时,创建从基类继承的类。 For Example: 例如:

template<class P> class Socket {
  protected:
   int sock;
   char datagram[4096];
   struct sockaddr_in server;
   struct sockaddr_in b;
  public:
   void dport(int port){server.sin_port=htons(port);}
   int CONNECT(){return connect(sock , (struct sockaddr *)&server , sizeof(server));};
  template <class Dst> inline void dst(Dst d){server.sin_addr.s_addr=inet_addr(d);}
  template <class Src> void src(Src s){b.sin_addr.s_addr=inet_addr(s);}  
  int LISTEN(int port){b.sin_port=htons(port); return bind(sock,
  (sockaddr*)&b, sizeof(b));}

There are several ways you can specialize at this point. 此时,您可以通过几种方法进行专业化。 My favorite would be to create new classes that inherit by passing their own name as the template argument to base. 我最喜欢的是创建新类,这些新类通过将自己的名称作为模板参数传递给base来继承。

class UDP : public Socket<UDP> {
public:
    UDP(){server.sin_family=AF_INET;
    this->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);}
    template <class Msg> int SEND(Msg m, int length){
    return sendto(this->sock, m, length, MSG_DONTWAIT, (sockaddr*)&this-
    >server, sizeof(this->server));}
    void RECV(void* buf, size_t size){socklen_t fromlen = sizeof(sockaddr);
    ssize_t i = recvfrom(this->sock, buf, size, MSG_WAITALL,
    (sockaddr*)&this->b, &fromlen);}
};

class TCP : public Socket<TCP> {
public:
 TCP(){this->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); this-
 >server.sin_family=AF_INET;}
 int SEND(std::string buf){return send(this->sock, buf.c_str(), buf.size(), 0);}   //TODO: Error Handling
 void RECV(){char cur; while (read(this->sock, &cur, 1) > 0 ) {cout << cur;}}};

Now UDP sockets use recvfrom() and sendto() while TCP sockets use send() and read(). 现在,UDP套接字使用recvfrom()和sendto(),而TCP套接字使用send()和read()。 All of these calls are now valid: 所有这些调用现在都有效:

Socket<TCP> t1;
Socket<UDP> u1;
TCP t2;
UDP u2;

I could not figure out any way to write specializations of the base class without duplicating code with each one. 如果不对每个基类重复编写代码,我想不出任何方法编写基类的专业化知识。 It's easier to create derived classes. 创建派生类更容易。

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

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