我遇到了一个问题,我正在尝试解决我想拥有一些抽象基类的地方,这些基础是从多个类中继承的,派生可以选择地将其方法覆盖而无需覆盖宣布另一个课程。我在这里举例说明我要实现的目标:
#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;
}
从理论上讲,输出将是:
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
如果有一种方法可以通过某种设计模式完成此操作,或者我使用的方法不好,请告诉我。我正在使用C 11。
您的用例尖叫"具有约束的模板"。您缺少的是如何检查和编码模板参数从正确的类继承。您可以使用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_
{
};
这是其工作原理:
std::enable_if
将具有type
(在我们的情况下,int
),如果布尔表达式为feed是正确的。否则,那里没有类型,并且模板不会编译。如果那里有类型,那么我们获得了一个非类型模板参数,我们将其提供0
的默认值。分配默认值是使我们能够使用两个参数实例化模板的原因。
您会在<type_traits>
标题中找到这些实用程序,等等。
我对这个主题很感兴趣,所以我有一些策略。我认为插座程序是此类抽象的完美演示。最简单的事情之一是在您声明的类的任何对象中声明具有功能和变量的基本标头。然后创建从基类继承的类,当本身设置为模板参数。例如:
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));}
目前有几种专业的方法。我最喜欢的是创建通过将自己的名称作为模板参数传递给基础的新类,以继承。
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;}}};
现在UDP插座使用recvFrom()和sendto(),而TCP套接字使用send()和read()。所有这些调用现在都是有效的:
Socket<TCP> t1;
Socket<UDP> u1;
TCP t2;
UDP u2;
我找不到任何方法来编写基础类的专业,而无需与每个代码复制代码。创建派生类更容易。