looking for solution of c++ member function override (non virtual) - c++

I've two classes:
struct A {
template <typename T>
void print(T& t){
// do sth specific for A
}
};
struct B : A {
template <typename T>
void print(T& t){
// do sth specific for B
}
};
In such case, the more general Base class with virtual functions (which A and B both inherit from) cannot be compiled, since there is no virtual for template. As I try to delegate generally all A or B objects under same "interface", does anyone has the idea to resolve such problem? Thank you in advance.
Sincerely,
Jun

You can think about using using CRTP.
template<typename Derived>
struct Base {
template <typename T>
void print(T& t){
static_cast<Derived*>(this)->print(t);
}
};
struct A : Base<A> {
// template print
};
struct B : Base<B> {
// template print
};
Example Usage:
template<typename T, typename ARG>
void foo (Base<T>* p, ARG &a)
{
p->print(a);
}
This method will be called as,
foo(pA, i); // pA is A*, i is int
foo(pB, d); // pB is B*, d is double
Here is another demo code.

Using a proxy class to get B's method
class A {
public:
friend class CProxyB;
virtual CProxyB* GetCProxyB() = 0;
};
class B;
class CProxyB
{
public:
CProxyB(B* b){mb = b;}
template <typename T>
void printB(T& t)
{
mb->print(t);
}
B* mb;
};
class B:public A {
public:
virtual CProxyB* GetCProxyB(){return new CProxyB(this);};
template <typename T>
void print(T& t){
printf("OK!!!!!\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new B;
CProxyB* pb = a->GetCProxyB();
int t = 0;
pb->printB(t);
return 0;
}

Two options:
Option one: Virtualize the method where if the user does not provide an implementation, the Base class' is used.
template <typename T>
struct A {
virtual void print(T& t);
};
template <typename T>
void A::print(T& t) {
// do sth specific for A
}
template <typename T>
struct B : A {
virtual void print(T& t);
};
void B::print(T& t) {
// do sth specific for B
}
Option two: Abstract the method where if the user does not provide an implementation, the code will not compile.
template <typename T>
struct A {
virtual void print(T& t)=0;
};
template <typename T>
struct B : A {
virtual void print(T& t){
// do sth specific for B
}
};
template <typename T>
void B::print(T& t){
// do sth specific for B
}
Other than the above mentioned, if you do not make them virtual, the Derived class will Shadow the Base class method and that is most certainly not what you intended. Hence, impossible.

my question is how to use single pointer to different A or B objects.
You can do this without virtual functions per-se. But all you will really be doing is writing an implementation of a V-table and virtual functions.
If I were going to manually implement virtual functions, I would base it all on a Boost.Variant object. The variant would effectively hold the member data for each class. To call a function, you use a variant visitor functor. Each "virtual function" would have its own visitor functor, which would have different overloads of operator() for each of the possible types within the variant.
So you might have this:
typedef boost::variant<StructA, StructB, StructC> VirtualClass;
You could store any one of those objects in the variant. You would call a "virtual function" on the object like this:
VirtualClass someObject(StructA());
boost::apply_visitor(FunctorA(), someObject);
The class FunctorA is your virtual function implementation. It is a visitor, defined like this:
class FunctorA : public boost::static_visitor<>
{
void operator()(StructA &arg){
//Do something for StructA
}
void operator()(StructB &arg){
//Do something for StructB
}
void operator()(StructC &arg){
//Do something for StructC
}
}
Visitors can have return values, which are returned by apply_visitor. They can take arguments, by storing the arguments as members of the visitor class. And so forth.
Best of all, if you ever change your variant type, to add new "derived classes", you will get compiler errors for any functors that don't have overloads for the new types.
But to be honest, you should just be using virtual functions.

By using CRTP(Curiously recurring template pattern), you can achieve static polymorphsim without virtual.
#include <iostream>
using namespace std;
#define MSG(msg) cout << msg << endl;
template<class Derived>
class Base{
public:
void print()
{
static_cast<Derived*>(this)->print();
}
};
class Derived1 : public Base<Derived1>
{
public:
void print()
{
MSG("Derived 1::print");
}
};
class Derived2 : public Base<Derived2>
{
public:
void print()
{
MSG("Derived 2::print");
}
};
template<class T>
void callme(Base<T>& p)
{
p.print();
}
int main()
{
Base<Derived1> p1;
Base<Derived2> p2;
callme(p1);
callme(p2);
system("pause");
return 0;
}
//Result :
//Derived 1::print
//Derived 2::print

Related

Use base class implementation when base is template type

I have a class that receives its base type as a template arg and I want my derived class to call a function, print. This function should use the derived implementation by default but if the base class has a print function it should use the base implementation.
#include <iostream>
class BaseWithPrint {
public:
static void print(int i) { std::cout << "Base::print\n"; }
};
class BaseWithoutPrint {
};
template <typename B>
class Derived : public B {
public:
static void print(bool b) { std::cout << "Derived::bool_print\n"; }
template <typename T>
static void print(T t) { std::cout << "Derived::print\n"; }
void Foo() {
print(1);
print(true);
print("foo");
}
};
int main()
{
Derived<BaseWithPrint> d1;
d1.Foo();
Derived<BaseWithoutPrint> d2;
d2.Foo();
return 0;
}
This code only ever calls the Derived version of print.
Code can be seen at
https://onlinegdb.com/N2IKgp0FY
If you know that the base class will have some kind of print, then you can add using B::print to your derived class. If a perfect match isn't found in the derived, then it'll check the base.
Demo
To handle it for the case where there may be a base print, I think you need to resort to SFINAE. The best SFINAE approach is really going to depend on your real world situation. Here's how I solved your example problem:
template <class T, class = void>
struct if_no_print_add_an_unusable_one : T {
// only ever called if derived calls with no args and neither
// the derived class nor the parent classes had that print.
// ie. Maybe best to force a compile fail:
void print();
};
template <class T>
struct if_no_print_add_an_unusable_one <T, decltype(T().print(int()))> : T {};
//====================================================================
template <class B>
class Derived : public if_no_print_add_an_unusable_one<B> {
using Parent = if_no_print_add_an_unusable_one<B>;
using Parent::print;
public:
// ... same as before
};
Demo

How to override a templated function from non-templated parent class [duplicate]

Is it possible to declare some type of base class with template methods which i can override in derived classes? Following example:
#include <iostream>
#include <stdexcept>
#include <string>
class Base
{
public:
template<typename T>
std::string method() { return "Base"; }
};
class Derived : public Base
{
public:
template<typename T>
std::string method() override { return "Derived"; }
};
int main()
{
Base *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
I would expect Derived as the output but it is Base. I assume it is necessary to make a templated wrapper class which receives the implementing class as the template parameter. But i want to make sure.
1) Your functions, in order to be polymorphic, should be marked with virtual
2) Templated functions are instantiated at the POI and can't be virtual (what is the signature??How many vtable entries do you reserve?). Templated functions are a compile-time mechanism, virtual functions a runtime one.
Some possible solutions involve:
Change design (recommended)
Follow another approach e.g. multimethod by Andrei Alexandrescu (http://www.icodeguru.com/CPP/ModernCppDesign/0201704315_ch11.html)
Template methods cannot be virtual. One solution is to use static polymorphism to simulate the behavior of "template virtual" methods:
#include <iostream>
#include <stdexcept>
#include <string>
template<typename D>
class Base
{
template<typename T>
std::string _method() { return "Base"; }
public:
template<typename T>
std::string method()
{
return static_cast<D&>(*this).template _method<T>();
}
};
class Derived : public Base<Derived>
{
friend class Base<Derived>;
template<typename T>
std::string _method() { return "Derived"; }
public:
//...
};
int main()
{
Base<Derived> *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
where method is the interface and _method is the implementation. To simulate a pure virtual method, _method would absent from Base.
Unfortunately, this way Base changes to Base<Derived> so you can no longer e.g. have a container of Base*.
Also note that for a const method, static_cast<D&> changes to static_cast<const D&>. Similarly, for an rvalue-reference (&&) method, it changes to static_cast<D&&>.
Another possible aproach to make your example work as you expect is to use std::function:
class Base {
public:
Base() {
virtualFunction = [] () -> string { return {"Base"}; };
}
template <class T> string do_smth() { return virtualFunction(); }
function<string()> virtualFunction;
};
class Derived : public Base {
public:
Derived() {
virtualFunction = [] () -> string { return {"Derived"}; };
}
};
int main() {
auto ptr = unique_ptr<Base>(new Derived);
cout << ptr->do_smth<bool>() << endl;
}
This outputs "Derived". I'm not sure that this is what you realy want, but I hope it will help you..
I had the same problem, but I actually came up with a working solution. The best way to show the solution is by an example:
What we want(doesn't work, since you can't have virtual templates):
class Base
{
template <class T>
virtual T func(T a, T b) {};
}
class Derived
{
template <class T>
T func(T a, T b) { return a + b; };
}
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
The solution(prints 3HelloWorld0.3):
class BaseType
{
public:
virtual BaseType* add(BaseType* b) { return {}; };
};
template <class T>
class Type : public BaseType
{
public:
Type(T t) : value(t) {};
BaseType* add(BaseType* b)
{
Type<T>* a = new Type<T>(value + ((Type<T>*)b)->value);
return a;
};
T getValue() { return value; };
private:
T value;
};
class Base
{
public:
virtual BaseType* function(BaseType* a, BaseType* b) { return {}; };
template <class T>
T func(T a, T b)
{
BaseType* argA = new Type<T>(a);
BaseType* argB = new Type<T>(b);
BaseType* value = this->function(argA, argB);
T result = ((Type<T>*)value)->getValue();
delete argA;
delete argB;
delete value;
return result;
};
};
class Derived : public Base
{
public:
BaseType* function(BaseType* a, BaseType* b)
{
return a->add(b);
};
};
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
We use the BaseType class to represent any datatype or class you would usually use in a template. The members(and possibly operators) you would use in a template are described here with the virtual tag. Note that the pointers are necessary in order to get the polymorphism to work.
Type is a template class that extends Derived. This actually represents a specific type, for example Type<int>. This class is very important, since it allows us to convert any type into the BaseType. The definition of the members we described described in BaseType are implemented here.
function is the function we want to override. Instead of using a real template we use pointers to BaseType to represent a typename. The actual template function is in the Base class defined as func. It basically just calls function and converts T to Type<T>. If we now extend from Base and override function, the new overridden function gets called for the derived class.

How to implement a fully generic Visitor for a hierarchy of classes in C++1x?

I'd like to implement a fully generic Visitor pattern using >= C++14 using template metaprogramming. I've already found a nice way to generalize the Visitor itself, but I'm having trouble defining the Visitables. The code below works, but I'd like the commented out code in main to work as well; in particular, I want to be able to have a collection of Visitables and apply a Visitor to each element.
Is what I'm trying to do even possible in C++?
Things I've tried:
class X : public Visitable<X>
This solves the problem of not having a suitable accept method in
X, but results in ambiguities X/A and X/B which the compiler
cannot resolve.
empty accept method in X without inheriting; works, but the
specialized accept methods in A and B are never called.
replace template class Visitor with regular class with function
template visit for arbitrary types; does not really change the
semantics, but is less readable IMHO
#include <iostream>
#include <vector>
template <typename I>
class Visitable {
public:
template <typename Visitor>
void accept(Visitor&& v) const {
v.visit(static_cast<const I&>(*this));
}
};
template <typename T, typename... Ts>
class Visitor : public Visitor<Ts...> {
public:
virtual void visit(const T& t);
};
template<typename T>
class Visitor<T> {
public:
virtual void visit(const T& t);
};
struct X {
// template <typename V> void accept(V&& v) const {};
};
struct A : public X, public Visitable<A> {};
struct B : public X, public Visitable<B> {};
class MyVisitor : public Visitor<A, B> {
public:
void visit(const A& a) override { std::cout << "Visiting A" << std::endl; }
void visit(const B& b) override { std::cout << "Visiting B" << std::endl; }
};
int main() {
MyVisitor v {};
// std::vector<X> elems { A(), B() };
// for (const auto& x : elems) {
// x.accept(v);
// }
A().accept(v);
B().accept(v);
}
There are a few issues with your current solution:
You don't have a polymorphic type that can represent any visitable type. This means that you don't have a way to properly store all your A and B values in a collection such that you can visit every element in the collection. X doesn't accomplish this because there is no way to require that a subclass of X also subclasses an instantiation of the Visitable class template.
You have no way of handling a mismatch of visitor/visitable types; you cannot guarantee that all values in your collection are visitable by some visitor type, without simply making the collection a vector<A> or vector<B>, in which case you lose the ability to store values of different visitable types in the same collection. You either need a way to handle at runtime the scenario of a visitor/visitable mismatch, or you need a much more complex template structure.
You cannot store polymorphic values directly in a collection. This is because vector stores its elements consecutively in memory, and therefore must assume a certain constant size for each element; by their nature polymorphic values have an unknown size. The solution is to use a collection of (smart) pointers to refer to polymorphic values elsewhere on the heap.
Here's a working adaptation of your original code:
#include <iostream>
#include <vector>
#include <memory>
template<typename T>
class Visitor;
class VisitorBase {
public:
virtual ~VisitorBase() {}
};
class VisitableBase {
public:
virtual void accept(VisitorBase& v) const = 0;
virtual ~VisitableBase() {}
};
template <typename I>
class Visitable : public VisitableBase {
public:
virtual void accept(VisitorBase& v) const {
auto visitor = dynamic_cast<Visitor<I> *>(&v);
if (visitor == nullptr) {
// TODO: handle invalid visitor type here
} else {
visitor->visit(dynamic_cast<const I &>(*this));
}
}
};
template<typename T>
class Visitor : public virtual VisitorBase {
public:
virtual void visit(const T& t) = 0;
};
struct A : public Visitable<A> {};
struct B : public Visitable<B> {};
class MyVisitor : public Visitor<A>, public Visitor<B> {
public:
void visit(const A& a) override { std::cout << "Visiting A" << std::endl; }
void visit(const B& b) override { std::cout << "Visiting B" << std::endl; }
};
int main() {
MyVisitor v {};
std::vector<std::shared_ptr<VisitableBase>> elems {
std::dynamic_pointer_cast<VisitableBase>(std::make_shared<A>()),
std::dynamic_pointer_cast<VisitableBase>(std::make_shared<B>())
};
for (const auto& x : elems) {
x->accept(v);
}
A().accept(v);
B().accept(v);
}
struct empty_t{};
template <class I, class B=empty_t>
class Visitable:public B {
public:
// ...
struct X : Visitable<X>{
};
struct A : Visitable<A,X> {};
struct B : Visitable<B,X> {};
Note however that dispatch here is static. And your vector contains Xs not As or Bs.
You probably want
template <class Visitor>
struct IVisitable {
virtual void accept(Visitor const& v) const = 0;
protected:
~IVisitable(){}
};
template <class I, class Visitor, class B=IVisitable<Visitor>>
struct Visitable {
virtual void accept(Visitor const& v) const override {
v.visit(static_cast<const I&>(*this));
}
};
which gets closer.
struct A; struct B; struct X;
struct X:Visitable<X, Visitor<A,B,X>> {
};
struct A :Visitable<A, Visitor<A,B,X>, X> {};
struct B :Visitable<B, Visitor<A,B,X>, X> {};
this still doesn't do what you want, because you have a vector of values. And polymorphic values require more work.
Make it a vector of unique ptrs to X, and add virtual ~X(){} and some * and make_uniques and this will do what you want.

Override template member in Interface

Is it possible to declare some type of base class with template methods which i can override in derived classes? Following example:
#include <iostream>
#include <stdexcept>
#include <string>
class Base
{
public:
template<typename T>
std::string method() { return "Base"; }
};
class Derived : public Base
{
public:
template<typename T>
std::string method() override { return "Derived"; }
};
int main()
{
Base *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
I would expect Derived as the output but it is Base. I assume it is necessary to make a templated wrapper class which receives the implementing class as the template parameter. But i want to make sure.
1) Your functions, in order to be polymorphic, should be marked with virtual
2) Templated functions are instantiated at the POI and can't be virtual (what is the signature??How many vtable entries do you reserve?). Templated functions are a compile-time mechanism, virtual functions a runtime one.
Some possible solutions involve:
Change design (recommended)
Follow another approach e.g. multimethod by Andrei Alexandrescu (http://www.icodeguru.com/CPP/ModernCppDesign/0201704315_ch11.html)
Template methods cannot be virtual. One solution is to use static polymorphism to simulate the behavior of "template virtual" methods:
#include <iostream>
#include <stdexcept>
#include <string>
template<typename D>
class Base
{
template<typename T>
std::string _method() { return "Base"; }
public:
template<typename T>
std::string method()
{
return static_cast<D&>(*this).template _method<T>();
}
};
class Derived : public Base<Derived>
{
friend class Base<Derived>;
template<typename T>
std::string _method() { return "Derived"; }
public:
//...
};
int main()
{
Base<Derived> *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
where method is the interface and _method is the implementation. To simulate a pure virtual method, _method would absent from Base.
Unfortunately, this way Base changes to Base<Derived> so you can no longer e.g. have a container of Base*.
Also note that for a const method, static_cast<D&> changes to static_cast<const D&>. Similarly, for an rvalue-reference (&&) method, it changes to static_cast<D&&>.
Another possible aproach to make your example work as you expect is to use std::function:
class Base {
public:
Base() {
virtualFunction = [] () -> string { return {"Base"}; };
}
template <class T> string do_smth() { return virtualFunction(); }
function<string()> virtualFunction;
};
class Derived : public Base {
public:
Derived() {
virtualFunction = [] () -> string { return {"Derived"}; };
}
};
int main() {
auto ptr = unique_ptr<Base>(new Derived);
cout << ptr->do_smth<bool>() << endl;
}
This outputs "Derived". I'm not sure that this is what you realy want, but I hope it will help you..
I had the same problem, but I actually came up with a working solution. The best way to show the solution is by an example:
What we want(doesn't work, since you can't have virtual templates):
class Base
{
template <class T>
virtual T func(T a, T b) {};
}
class Derived
{
template <class T>
T func(T a, T b) { return a + b; };
}
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
The solution(prints 3HelloWorld0.3):
class BaseType
{
public:
virtual BaseType* add(BaseType* b) { return {}; };
};
template <class T>
class Type : public BaseType
{
public:
Type(T t) : value(t) {};
BaseType* add(BaseType* b)
{
Type<T>* a = new Type<T>(value + ((Type<T>*)b)->value);
return a;
};
T getValue() { return value; };
private:
T value;
};
class Base
{
public:
virtual BaseType* function(BaseType* a, BaseType* b) { return {}; };
template <class T>
T func(T a, T b)
{
BaseType* argA = new Type<T>(a);
BaseType* argB = new Type<T>(b);
BaseType* value = this->function(argA, argB);
T result = ((Type<T>*)value)->getValue();
delete argA;
delete argB;
delete value;
return result;
};
};
class Derived : public Base
{
public:
BaseType* function(BaseType* a, BaseType* b)
{
return a->add(b);
};
};
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
We use the BaseType class to represent any datatype or class you would usually use in a template. The members(and possibly operators) you would use in a template are described here with the virtual tag. Note that the pointers are necessary in order to get the polymorphism to work.
Type is a template class that extends Derived. This actually represents a specific type, for example Type<int>. This class is very important, since it allows us to convert any type into the BaseType. The definition of the members we described described in BaseType are implemented here.
function is the function we want to override. Instead of using a real template we use pointers to BaseType to represent a typename. The actual template function is in the Base class defined as func. It basically just calls function and converts T to Type<T>. If we now extend from Base and override function, the new overridden function gets called for the derived class.

C++ interface style programming. Need a way out

template <typename T>
class BaseQueue
{
public :
virtual void push_back(T value) = 0;
//other virtual methods
};
template <typename T>
class BaseDeque: public virtual BaseQueue<T>
{
public:
virtual void push_front(T value) = 0;
//other virtual methods
};
//Realisation
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata;
public:
VectorQueue()
{
adata = array();
}
void push_back(T value)
{
adata.push_back(value);
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
VectorDeque<int> vd = VectorDeque<int>();//here is a error
int i;
std::cin >> i;
return 0;
}
I have such error: "C2259: 'VectorDeque' : cannot instantiate abstract class ...". How can I fix it? Class VectorQueue has realize every virtual method of BaseQueue class already. But the compiler doesn't know it. The only way I see is to write something like this:
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
void push_back(T value)
{
VectorQueue::push_back(value);
}
//repeat it fo every virtual method of BaseQueue class (interface)
};
But it's awful.
push_back from BaseQueue isn't implemented on the BaseDeque side of the inheritance chain, and thus the childmost class is still abstract.
I think you're trying to force a class relationship here that shouldn't exist. Note how in the standard library deque and vector are distinct container types and things like queue adapt those containers to very precise interfaces rather than trying to inherit.
Even if you solve your diamond issue (or follow #Mark B's advice and keep them separate), you have a few other issues in there:
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata; // if this is private, VectorDeque can't reach it
public:
// constructors have an initializer section
// member variables should be initialized there, not in the body
VectorQueue()
// : adata() // however, no need to explicitly call default constructor
{
// adata = array();
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>
{
void push_front(T value)
{
// if adata is protected, you can just access it. No need for scoping
/*VectorQueue::*/ adata.push_front(value);
// Error: std::vector doesn't have a method push_front.
// Perhaps you meant to use std::list?
}
};
Multiple inheritance and static polymorphism are of help, for instance:
// Abstract bases
template <typename T, typename Val>
class BaseQueue
{
public :
void push_back(Val val)
{
static_cast<T*>(this)->push_back(val);
}
// ...
};
template <typename T, typename Val>
class BaseDeque
{
public:
void push_front(Val val)
{
static_cast<T*>(this)->push_front(val);
}
// ...
};
// Concrete class
#include <deque>
template <typename Val>
class QueueDeque:
public BaseQueue<QueueDeque<Val>, Val>,
public BaseDeque<QueueDeque<Val>, Val>
{
std::deque<Val> vals;
public:
void push_front(Val val)
{
vals.push_front(val);
}
void push_back(Val val)
{
vals.push_back(val);
}
// etc..
};
int main()
{
QueueDeque<int> vd;// no more error
vd.push_front(5);
vd.push_back(0);
return 0;
}