This issue involves using templates to resolve virtual members in a Dispatch pattern.
Note: This is not the same as virtual template method questions already asked on StackOverflow. *
Edit 1: Corrected syntax errors, added clarifications.
Given the following:
#include <string>
#include <iostream>
class Field_Interface
{
public:
virtual std::string get_field_name(void) const = 0;
};
class Field_Integer : public Field_Interface
{
public:
std::string get_field_name(void) const
{ return "INT";}
};
class Field_String : public Field_Interface
{
public:
std::string get_field_name(void) const
{ return "VARCHAR";}
};
class Field_Double : public Field_Interface
{
public:
std::string get_field_name(void) const
{ return "DOUBLE";}
};
class Abstract_Visitor
{
public:
virtual void visit(const Field_Integer& fi) = 0;
virtual void visit(const Field_String& fi) = 0;
virtual void visit(const Field_Double& fi) = 0;
};
class Visitor_Name_Query_1 : public Abstract_Visitor
{
public:
template <class Field>
void visit(const Field& f)
{
std::cout << "Field name is: "
<< f.get_field_name()
<< "\n";
}
};
class Visitor_Name_Query_2 : public Abstract_Visitor
{
public:
void visit(const Field_Integer& fi)
{ print_field_name(fi); }
void visit(const Field_String& fi)
{ print_field_name(fi); }
void visit(const Field_Double& fi)
{ print_field_name(fi); }
private:
void print_field_name(const Field_Interface& fi)
{
std::cout << "Field name is: "
<< fi.get_field_name()
<< "\n";
}
};
int main(void)
{
Visitor_Name_Query_1 q1;
Field_Integer fi;
q1.visit(f1);
return 0;
}
The compiler is saying the templated method in Visitor_Name_Query_1 is not resolving the abstract interface from Abstract_Visitor.
Edit 2: Results from g++
# g++ -o main.exe main.cpp
main.cpp: In function `int main()':
main.cpp:75: error: cannot declare variable `q1' to be of type `Visitor_Name_Query_1'
main.cpp:75: error: because the following virtual functions are abstract:
main.cpp:35: error: virtual void Abstract_Visitor::visit(const Field_Integer&)
main.cpp:36: error: virtual void Abstract_Visitor::visit(const Field_String&)
main.cpp:37: error: virtual void Abstract_Visitor::visit(const Field_Double&)
main.cpp:77: error: `f1' undeclared (first use this function)
main.cpp:77: error: (Each undeclared identifier is reported only once for each function it appears in.)
Visitor_Name_Query_1 is an attempt to simplify the class Visitor_Name_Query_2. When the number of visit methods grows beyond a simple quantity (like 5), maintenance becomes tedious. This is the reason for the template declaration.
When the template is expanded, with one of the field types, the declaration matches the one in Visitor_Name_Query_2.
So why is the compiler generating saying that class Visitor_Name_Query_1 is abstract?
Note: I am using Visual Studio 2008 on Windows Vista.
* The other posts involve using templates to create virtual method declarations. I'm using templates to create functions that implement the abstract methods.
So why is the compiler generating saying that class Visitor_Name_Query_1 is abstract?
Because the standard says so. §14.5.2 [temp.mem]/p4:
A specialization of a member function template does not override a
virtual function from a base class. [ Example:
class B {
virtual void f(int);
};
class D : public B {
template <class T> void f(T); // does not override B::f(int)
void f(int i) { f<>(i); } // overriding function that calls
// the template instantiation
};
—end example ]
It seems you really want the Abstract_Visitor to have a default implementation. If you move the template into the Abstract_Visitor, you can let each virtual visitor have the default implementation.
class Abstract_Visitor
{
template <class Field>
void visit(const Field& f)
{
std::cout << "Field name is: "
<< f.get_field_name()
<< "\n";
}
public:
virtual void visit(const Field_Integer& fi) { visit<>(fi); }
virtual void visit(const Field_String& fi) { visit<>(fi); }
virtual void visit(const Field_Double& fi) { visit<>(fi); }
};
As all field types have a common interface, you could simplify the problem by changing the interface if it is possible:
class Abstract_Visitor
{
public:
virtual void visit(const Field_Interface& f) = 0;
};
class Visitor_Name_Query_3 : public Abstract_Visitor
{
public:
void visit(const Field_Interface& f)
{
std::cout << "Field name is: "
<< f.get_field_name()
<< "\n";
}
};
Related
I'm familiar with polymorphism in general, but I'm fairly new to C++ in general and templates in particular. I have to following situation with a mixture of code that I cannot change (usage of a framework, all events and templated event listeners) and code under my control (clients in the example below).
#include <string>
#include <iostream>
#include <vector>
class EventBase {
public:
virtual std::string getData() const = 0;
};
class EventA : public EventBase {
public:
std::string getData() const override {
return "Event A";
}
};
class EventB : public EventBase {
public:
std::string getData() const override {
return "Event B";
}
};
template<class T_Event>
class IEventHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
virtual void onError() = 0;
};
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
std::cout << "ClientA::onError" << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
class ClientB : public ClientBase, public IEventHandler<EventB> {
public:
void onEvent(const EventB& e) override {
std::cout << "ClientB::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
std::cout << "ClientB::onError" << std::endl;
};
void startReceiving() override {
std::cout << "ClientB::startReceiving" << std::endl;
};
};
int main(int, char**) {
//User Code
ClientA ca;
ClientB cb;
std::vector<ClientBase*> baseClients;
baseClients.push_back(&ca);
baseClients.push_back(&cb);
for(const auto client : baseClients){
client->startReceiving();
}
//Framework Code
EventA a;
EventB b;
std::vector<IEventHandler<EventA>*> eventHandlersA;
std::vector<IEventHandler<EventB>*> eventHandlersB;
eventHandlersA.push_back(&ca);
eventHandlersA[0]->onError();
eventHandlersA[0]->onEvent(a);
eventHandlersB.push_back(&cb);
eventHandlersB[0]->onError();
eventHandlersB[0]->onEvent(b);
//User Code
for(const auto client : baseClients){
client->stopReceiving();
}
}
See here: https://onlinegdb.com/2MYQhC2G5
What I want to do now is to have a common default implementation of onError.
To do so, I tried at least four approaches. Only the second worked. It would be nice to hear from C++ savants if this approach 2 is actually the way to do it.
Approach 1
Simply put onError in ClientBase and remove it from derived clients.
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Fails on compile time with
error: variable type 'ClientA' is an abstract class
note: unimplemented pure virtual method 'onError' in 'ClientA'
Okay, it's abstract since it does not implement the methods needed from IEventHandler<EventA>
Approach 2
Fix the unimplemented method in ClientA but call the super class method implementation:
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
ClientBase::onError();
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Works, though under the hood I think other things are happening then originally intended (might be more of a delegation then inheritance).
Maybe mess around with templates?
Approach 3: Remove the IEventHandler from the derived clients
class ClientBase : public IEventHandler<EventBase> {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
virtual void onEvent(const EventBase& e) = 0;
};
class ClientA : public ClientBase {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Build system hates me:
error: non-virtual member function marked 'override' hides virtual member function
note: hidden overloaded virtual function 'ClientBase::onEvent' declared here: type mismatch at 1st parameter ('const EventBase &' vs 'const EventA &')
error: variable type 'ClientA' is an abstract class
note: unimplemented pure virtual method 'onEvent' in 'ClientA' - virtual void onEvent(const EventBase& e) = 0;
Okay, so you can override methods only if the signature matches exactly.
Approach 4: Make ClientBase templated
template<class T_Event>
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
virtual void onEvent(const T_Event& e) = 0;
};
class ClientA : public ClientBase<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Again, no success. This time my structures to track my clients would break:
std::vector<ClientBase*> baseClients; ----> error: use of class template 'ClientBase' requires template arguments
eventHandlersA.push_back(&ca); ---> error: no matching member function for call to 'push_back'
Do you have any more ideas on how to achieve the original goal? Or is sticking to approach 2 a good solution?
Your insights into approaches 1-3 are generally correct:
Approach 1 failed because ClientBase didn't inherit from IEventHandler<> which declared the virtual method.
Approach 2 is indeed a delegation, which is fine in my opinion. Virtual methods are already a delegation - under the hood a vtable is roughly equivalent to a set of function pointers. Delegating onError is just one more level of indirection, and hopefully something called onError isn't called frequently enough to make the performance penalty significant.
Approach 3 failed because anything overriding onEvent(const EventBase& e) needs to accept any EventBase&, per the contract.
Approach 4 failed because ClientBase<EventA> and ClientBase<EventB> are completely different types that don't share a common base. Templates are more like type factories than types - there's no relationship between instantiations.
If you want to make the this work with inheritance, you can spell out that common base explicitly by having a non-template ClientBase and a template layer in between to implement onError:
template <typename TEvent>
class ErrorHandlingClient : public ClientBase, public IEventHandler<TEvent> {
public:
virtual void onError() override { /* ... */ }
};
class ClientA : public ErrorHandlingClient<EventA> {
public:
void onEvent(const EventA& e) override { /* ... */ }
void startReceiving() override { /* ... */ }
};
class ClientB : public ErrorHandlingClient<EventB> {
public:
void onEvent(const EventB& e) override { /* ... */ }
void startReceiving() override { /* ... */ }
};
ClientA and ClientB will have different implemenations of onError because of the template, but they can both be casted to a common ClientBase type to store in a vector.
One last opinion - if you need an abstract class to get your desired code organization, it might be a sign that your concerns aren't separated: Maybe IEventHandler<T> should really be two interfaces, or maybe error handling should be owned by some other entity.
The basic problem is having a class template with a virtual method that does not need the template parameter. It is not wrong per se, but it can easily make one's life mighty inconvenient.
The problem with your Approach 1 is having more than one source node in the inheritance graph that has errorHandler. These functions are unrelated. Here is a simplified demo:
struct X { virtual void foo() = 0; };
struct Y { virtual void foo() {} };
struct XY : X, Y {};
XY is still abstract, despite having an implementation of foo, because there are two unrelated foos in it and the only way to unify them is to override foo in XY. This surprises a lot of people.
The best practice here (as I understand it) is moving the offending function to a common base class of X, Y and XY (create one if needed). Up the hierarchy, not down or sideways. It should be inherited virtually (not a diamond-of-death problem, since it is an ABC with no data members).
So don't do this:
template<class T_Event>
class IEventHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
virtual void onError() = 0;
};
Do this instead:
class IErrorHandler {
public:
virtual void onError() = 0;
// or whatever default implementation you want
};
template<class T_Event>
class IEventHandler : public virtual /* XXX Important! */ IErrorHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
};
class ClientBase : public virtual IErrorHandler {
virtual void onError() override {} // whatever
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
virtual void onEvent(const EventA& e) {}
};
Live Demo.
Note, the MSVC compiler may issue a warning (C4250) on this. Ignore or silence it. For your convenience, here is a collection of SO posts on this topic.
Consider I have two pure virtual classes, one deriving from the another and a concrete class deriving from the last mentioned:
#include <iostream>
#include <string>
class Abstract1
{
public:
virtual ~Abstract1() { };
virtual void method(int a) = 0;
protected:
Abstract1() = default;
};
class Abstract2: public Abstract1
{
public:
virtual ~Abstract2() { };
virtual void method(char c, std::string s) = 0;
protected:
Abstract2() = default;
};
class Concrete : public Abstract2
{
public:
void method(int a) override
{
std::cout << __PRETTY_FUNCTION__ << "a: " << a << std::endl;
}
void method(char c, std::string s) override
{
std::cout << __PRETTY_FUNCTION__ << "c: " << c << "; s: " << s << std::endl;
}
};
When I create a pointer of the type Abstract2* I can't have access to the override method from Abstract1.
int main()
{
Concrete c;
c.method(42);
c.method('a', std::string("string"));
Abstract2 *ptr_a2 = &c;
ptr_a2->method(13); //Error
ptr_a2->method('b', std::string("string2"));
}
I got the following error, saying that the only existing method is the Absctract2 overloaded:
<source>: In function 'int main()':
<source>:49:22: error: no matching function for call to 'Abstract2::method(int)'
49 | ptr_a2->method(13);
| ^
<source>:22:18: note: candidate: 'virtual void Abstract2::method(char, std::string)'
22 | virtual void method(char c, std::string s) = 0;
| ^~~~~~
<source>:22:18: note: candidate expects 2 arguments, 1 provided
Does anybody know why does it happen or how to fix it?
I mean, the only reasonable solution I got was to add
virtual void method(int a) override = 0;
inside Abstract2 class.
Is it a case of "name hiding"? Why only on pointer and not on the Concrete class then? The number of parameters are different is not only a close-type thing.
Here's a link to play with it online where the example was created:
https://godbolt.org/z/gxKpzN
Yes, the name is hidden in Abstract2 (but visible again in Concrete, where the override is declared). The easiest way to make it accessible in Abstract2 is to add a using statement:
class Abstract2: public Abstract1
{
public:
using Abstract1::method;
virtual void method(char c, std::string s) = 0;
};
Note that it's not relevant whether the member function is pure virtual or has a definition, and we see the same whether looking at a concrete Abstract2 or a reference or pointer to type Abstract2.
I am trying to use abstract classes and I met some problems when defining constructors of derived class. I wrote the following code, based on the answer to this question.
#include <string>
#include <iostream>
class ICommand {
private:
ICommand();
public:
const std::string name;
ICommand(const std::string& name) : name(name) { }
virtual void callMe();
virtual void callMe2();
};
class MyCommand : public ICommand {
public:
int x;
MyCommand(const std::string& name) : ICommand(name) { }
MyCommand(const std::string& name, int x) : ICommand(name), x(x) { }
void callMe() {
std::cout << name << "\n";
}
void callMe2() {
std::cout << name << x << "\n";
}
};
void f(std::string name) {
MyCommand A(name);
A.callMe();
}
This compiles without error. However my aim is to build a .so for a R package). In the R installation process, the .so is build without error, with clang++ -shared, but then there is a verification step which produces
unable to load shared object '/path/object.so':
/path/object.so: undefined symbol: _ZTI8ICommand
I've met this kind of problem before, and there are workarounds — not calling Icommand(name) is fairly simple, but I want to understand what is happening there, and, if possible, how to avoid the workaround.
Thanks in advance for your thoughts.
Answer
For the convenience of future readers: the only necessary change here is to replace the definition of virtual functions in the abstract class by
virtual void callMe() = 0;
virtual void callMe2() = 0;
which makes them pure virtual functions. Why this settles the problem totally beats me.
With the:
class MyClass {
private:
MyClass();
};
You are deleting a default constructor. If you want to call a default constructor then (declare or) define or don't define one but don't delete it. Your derived class default constructor will call the base class default constructor:
#include <string>
#include <iostream>
#include <memory>
class ICommand {
public:
std::string name;
ICommand() : name("The name") { std::cout << "Default base class constructor." << std::endl; }
virtual void callMe() = 0;
};
class MyCommand : public ICommand {
public:
MyCommand(){ std::cout << "Default derived class constructor." << std::endl; };
void callMe() override {
std::cout << name << std::endl;
}
};
void f2(const std::string& name) {
std::shared_ptr<ICommand> p = std::make_shared<MyCommand>();
p->callMe();
}
int main(){
f2("asdasd");
}
Part 2:
If you are trying to use the above classes in a polymorphic way then make your ICommand member functions pure virtual:
virtual void callMe() = 0;
virtual void callMe2() = 0;
Modify the void f function to:
void f(const std::string& name) {
std::shared_ptr<ICommand> p = std::make_shared<MyCommand>(name);
p->callMe();
}
Live example on Coliru.
class ICommand {
private:
ICommand() = default;
public:
const std::string name;
ICommand(const std::string& name) : name(name) { }
virtual ~ICommand() = default;
virtual void callMe() = 0;
virtual void callMe2() = 0;
};
That may sound kind of strange, and I may have to refactor my code at some point but I would need to generate the pure virtual base class methods with a template function. Is it doable with C++11 (variadic templates ?) ?
Example :
struct I
{
virtual void foo(int) = 0;
virtual void foo(float) = 0;
};
struct S : public I
{
template<typename T>
void foo(T t) { /*do the same symbolic stuff on t*/ }
};
int main()
{
S s;
s.foo(0);
s.foo(0.0f);
return 0;
}
Giving the following error (clang) :
main.cpp:65:7: error: variable type 'S' is an abstract class
S s;
^
main.cpp:53:18: note: unimplemented pure virtual method 'foo' in 'S'
virtual void foo(int) = 0;
^
main.cpp:54:18: note: unimplemented pure virtual method 'foo' in 'S'
virtual void foo(float) = 0;
^
1 error generated.
You can't do that.
A signature of a template method is not the same of a non-template method.
And you can't have a virtual template method.
You can't do it directly, but you can use forwarders to have a common implementation:
struct S : public I
{
private:
template<typename T>
void foo_impl(T t) { /*do the same symbolic stuff on t*/ }
public:
virtual void foo(int v) { foo_impl(v); }
virtual void foo(float v) { foo_impl(v); }
};
parent class
class Test {
public:
Test(){};
virtual ~Test(){};
void print() { cout<<1<<endl;};
};
sub class .h define
class TestSub: public Test {
public:
TestSub();
virtual ~TestSub();
};
sub class .cpp implements
#include "TestSub.h"
TestSub::TestSub() {
}
TestSub::~TestSub() {
}
void TestSub::print(){
cout<<2<<endl;
}
int main(){
TestSub *t=new TestSub();
t->print();
}
why:
..\src\TestSub.cpp:17:21: error: no 'void TestSub::print()' member function declared in class 'TestSub'
You have 2 errors:
First you have to declare you function in TestSub as : void print();
Second you have to specify a return type for you implementation, C++ do not accept default return type such as C, so you must convert your implementation to void TestSub::print() {...}
print() funciton is not declared in TestSub class.
class TestSub: public Test {
public:
TestSub();
void print(); // add declaration.
virtual ~TestSub();
};
I guess you also intended to make Test::print virtual?
class Test {
public:
Test(){}
virtual ~Test(){}
virtual void print() { std::cout << 1 << std::endl;}
};
If you don't specify the return type C defaults to int as return type of a function. Which doesn't match the void return type of the declaration in the class.