想象一下这个简单的基类:
struct simple_http_service
{
virtual reply http_get(…);
virtual reply http_post(…);
virtual reply http_delete(…);
// etc.
};
我希望防止用户继承此类而不覆盖至少其中一个方法,并防止他们实例化
simple_http_service
。有没有一些好的方式来做到这一点?
想象一下这个简单的基类:
struct simple_http_service
{
virtual reply http_get(…);
virtual reply http_post(…);
virtual reply http_delete(…);
// etc.
};
simple_http_service
。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;
};
std::bind
提供不同的服务实例,以控制在底层模型中分派到不同操作,或者您可以从单个服务中分派到不同的类,这种方法比继承更加灵活。 - David Rodríguez - dribeas我认为所有这些函数都应该是纯虚函数。你发布的结构实际上是一个接口。如果不是所有函数都是必需的,那么派生结构体应该仅为与它们无关的函数提供空实现。
我不太明白为什么你想要为其他两个函数提供默认实现,但在HTTP请求的情况下至少需要一个用户定义的函数。
如果所有函数都使用彼此来使用现有代码实现某些功能,则很清楚。
想象一下这个类的例子:
class Cls
{
public:
virtual std::string toString()=0;
virtual std::string serialize()=0;
};
有一个类是可转换为字符串和可序列化为字符串的。但如果其中一个没有被实现,你想调用第二个,那么这将是一个选项:
class Cls
{
public:
virtual std::string toString() //calls serialize() by default
{
return this->serialize();
}
virtual std::string serialize() //calls toString()
{
return this->toString();
}
virtual ~Cls()=0; //force the class to be abstract
}; Cls::~Cls(){}
但现在有一个问题是从Cls派生,但没有覆盖至少一个函数。 如果没有覆盖,则在运行时会进入无限递归。 如果这是您的问题之一,则有一个运行时解决方案,下面的代码如果出现此类问题则不执行任何操作。
class Cls
{
public:
virtual std::string toString()
{
if ((void*)(this->*(&Cls::serialize)) != (void*)(&Cls::serialize))
{//checks if the current implemetation is not equal to the default one
return this->serialize();
}
else
{
return ""; //default return value
}
}
virtual std::string serialize()
{
if ((void*)(this->*(&Cls::toString))!=(void*)((&Cls::toString)))
{
return this->toString();
}
else
{
return "";
}
}
virtual ~Cls()=0;
}; Cls::~Cls(){}
这在GCC上编译通过,但会在屏幕上填充有关从funcptr到void *的奇怪转换的警告。至少它按预期工作。可能有一些元编程编译时解决方案,需要考虑一下。
附录1,测试成员函数之间的比较:
真的很奇怪。
#include <iostream>
class Base
{
public:
virtual int test()
{
//default imp
return 0;
}
};
class Der : public Base
{
public:
int test() override
{
//custom imp
return 1;
}
};
int main()
{
Der a;
Base b;
std::cout << ((&Der::test) == (&Base::test)) << std::endl;//1: wrong
//they are not equal
//but for some reason the output is "true"
//so direct comparisons do not work
//however
//if you convert that pointer to void*
//everything works
std::cout << ((void*)(&Der::test) == (void*)(&Base::test) ) << std::endl; //0:right
std::cout << ((void*)(a.*(&Base::test)) == (void*)(&Base::test) ) << std::endl;//0:right
std::cout << ((void*)(b.*(&Base::test)) == (void*)(&Base::test) ) << std::endl;//1:right
std::cout << ((void*)(&(a.test)) == (void*)(&(b.test)) ) << std::endl; //0:right
//so if you want to compare two functions
//cast them to void*
//works in any cases
//'-Wno-pmf-conversions' compiler flag to inhibit warnings about casting
system("pause");
return 0;
}
附录2,获取函数真实地址的步骤:
Cls::serialize; //the function object itself
&Cls::serialize; //its member pointer
(void*)(&Cls::serialize); //extracting real address of the function for the comparison
(this->*&Cls::serialize); //again, a member pointer
(void*)(this->*&Cls::serialize); //extracting real address
// │ │ └── Getting "pointer" to a member function of the class
// │ └───── Then binding 'this' to that function, recall that if the function is virtual, '->*' returns a mamber pointer to it's custom implementation, not the default one.
// └────────────── Then getting the real address
// it looks like 'this->*&Cls::serialize' does the same as '&this->serialize'
// but in practice it's not quite right
// '&this->serialize' returns the function pointer based on 'this' type
// therefore, comparison breaks, as inside of a base class 'this' always has the base type
// so you always receive the default implementation pointer
// 'this->*&Cls::serialize' does the same
// but now if 'serialize' is virtual
// it takes it into account and sends back its' custom implementation pointer
// (void*) casting is required because you need to compare functions' real addresses
// if you compare member pointers of a single virtual function
// they seem to be equal while they are, in fact, not
如何检查派生类是否实现了基类的虚函数在这里。
(void*)(this->*(&Cls::serialize))
是什么? - curiousguy如果您知道要让派生类覆盖哪些方法,只需声明该方法为纯虚函数。
例如,将http_get声明为纯虚函数:
struct simple_http_service
{
virtual reply http_get(…) = 0;
virtual reply http_post(…);
virtual reply http_delete(…);
// etc.
};