I don't not quite understand why do you want to provide default implementation for other two functions but require at least one of them to be user-defined in the case of http requests.
It's clear if all functions are using each other to implement some functionality using existing code.
Imagine the example with that class:
class Cls
{
public:
virtual std::string toString()=0;
virtual std::string serialize()=0;
};
There is a class that is string-convertible and string-serializable. But if one of these is not implemented, you want to call the second instead, so that would be an option:
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(){}
But now there is the problem with deriving from Cls but not overriding at least one of the functions. If no overriding is made, at runtime you just enter infinite recursion. If this is one of your problems, there is a run-time solution, the code below is just not doing anything if such a problem occurs.
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(){}
This compiles on GCC, but fills your screen with warnings about strange convertion from funcptr to void*. At least it works as intended. There may be some metaprogramming compile-time solutions, need to think about it.
Appendix1, testing comparison between member funcs:
It is really weird
#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;
}
Appendix2, steps of getting real address of the function:
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
The issue of checking if the derived class has implemented some of the base class virtual functions is here