I do have some general data type and some derived type(s):
class abstract_data { virtual void foo() {}; };
class derived_data : public abstract_data { void foo() {} };
I want to write some classes that work on that data. What I would like to do is:
class abstract_worker {
public:
virtual void apply(abstract_data&) = 0;
};
class derived_worker : public abstract_worker {
public:
void apply(derived_data&) {} ;
};
This is not working, because the compiler asks me to implement void apply(abstract_data&). I see two alternatives.
1.alternative:
class abstract_worker {
public:
virtual void apply(abstract_data&) = 0;
};
class derived_worker : public abstract_worker {
public:
void apply(abstract_data& data) {
derived_data& internal_data = dynamic_cast<derived_data&>(data);
}
};
2. alternative:
template<class DATA_TYPE>
class abstract_worker {
public:
virtual void apply(DATA_TYPE&) = 0;
};
class derived_worker : public abstract_worker<derived_data> {
public:
void apply(derived_data&) { }
};
I don't like both of them. In the 1st alternative the parameter is declared as abstract_data& even though it really needs to be derived_data&.
In the 2nd alternative it gets lost that the parameter is of type abstract_data&. This is even more problematic if apply(abstract_data&) is not pure virtual, but uses some functionality of abstract_data. You run in the situtation where abstract_data& is implicitely required as DATA_TYPE, but not explicitely declared as such.
However, I do want to keep the type relationships.
Is there another way? If not which one would you prefer?
You might use static assert to prevent DATA_TYPE not inheriting from abstract_data:
#include
class abstract_data { virtual void foo() {}; };
class derived_data : public abstract_data { void foo() {} };
class faulty_data { void foo() {} };
template<class DATA_TYPE>
class abstract_worker {
static_assert(std::is_base_of<abstract_data, DATA_TYPE>::value, "DATA_TYPE does not inherit from abstract_data");
public:
virtual void apply(DATA_TYPE&) = 0;
};
class derived_worker : public abstract_worker<derived_data> {
public:
void apply(derived_data&) {}
};
class faulty_worker : public abstract_worker<faulty_data> {
public:
void apply(faulty_data&) {}
};
Output while compiling:
1>------ Build started: Project: Test_Call, Configuration: Debug Win32 ------
1> Source.cpp
1><PROJ_PATH>\source.cpp(9): error C2338: DATA_TYPE does not inherit from abstract_data
1> <PROJ_PATH>\source.cpp(20): note: see reference to class template instantiation 'abstract_worker<faulty_data>' being compiled
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Related
When trying to compile the snippet below, I got the error stated:
error C2259: 'cTest': cannot instantiate abstract class
note: due to the following members:
note: void iTest::log(iTest::eLevel): is abstract
note: see declaration of 'iTest::log'
The abstract member function has been defined with the same signature.
Removing the second enum solves the problem though, it wasn't intended anyway.
But still I don't know why a C2259 is given and I can only find that the member should be defined to fix.
class iTest
{
public:
enum eLevel
{
Info,
};
virtual void foo( eLevel l ) = 0;
};
class cTest : public iTest
{
public:
enum eLevel
{
Info,
};
virtual void foo( eLevel l )
{
}
};
int main()
{
iTest* t = new cTest();
}
The reason why you get this error is because the second definition of iTest::foo and cTest::foo do not have the same signature and thus ctest does not implement iTest::foo.
With full names, your declarations are as follows:
class iTest
{
public:
enum eLevel
{
Info,
};
virtual void foo( iTest::eLevel l ) = 0;
};
class cTest : public iTest
{
public:
enum eLevel
{
Info,
};
virtual void foo( cTest::eLevel l )
{
}
};
As one can see, foo(iTest::eLevel) is not the same as foo(cTest::eLevel), thus cTest is still an abstract class and cannot be instantiated.
You can either remove cTest::eLevel completely, or declare cTest::foo as
class cTest : public iTest
{
public:
enum eLevel
{
Info,
};
virtual void foo( iTest::eLevel l )
{
}
};
Say I've got the following (pseudo-)code:
class base{
public:
virtual void callMe() = 0;
virtual void doRender() = 0;
}
class a : public base{
public:
virtual void callMe(){/*doA*/} override;
}
class b : public base{
public:
virtual void callMe(){/*doB*/} override;
}
class myClass : public base, public a, public b{
public:
virtual void doRender(){
this->a::callMe();
this->b::callMe();
} override;
}
Would there be a way to write this differently? Something like:
class myClass : public base, public a, public b{
public:
virtual void doRender(){
this->allSupers::callMe();
} override;
}
My goal with this would be to have a base class that can be extended to have different "features", all of which have to be executed on doRender.
I know I could of course keep track of these functions by means of a function pointer list in base, in which the subclasses put their own functions when constructed, but I'd like to avoid that. Having to iterate over these functions still gives me at least three lines of code in my final doRender. (Or one long unreadable line.)
I'm open for suggestions using templates.
Depending on you actual problem at hand, you might be able to use the mixin-style. Essentially you can have each class call the next callMe at the end (or begining) of their own callMe. One benefit is that callMe does not need to be a virtual function. Here is a minimal example (online):
#include <iostream>
class base
{
public:
void callMe() {}; // Empty base case
virtual void doRender() = 0;
};
template <class super>
class a : public super
{
public:
void callMe()
{
std::cout << "doA" << '\n';
super::callMe(); // Call the next
};
};
template <class super>
class b : public super
{
public:
void callMe()
{
std::cout << "doB" << '\n';
super::callMe(); // Call the next
};
};
template <class super>
class myClass_t : public super
{
public:
void doRender()
{
super::callMe();
};
};
using myClass = myClass_t<a<b<base> > >; // Defining the order of evaluation;
int main()
{
myClass m;
m.doRender();
}
With variadic template, you may do:
template <typename ... Ts>
class myClassTs : public base, public Ts...
{
public:
virtual void doRender(){
int dummy[] = {0, (Ts::callMe(), void(), 0)...};
static_cast<void>(dummy); // Silent warning for unused variable
} override;
}
using myClass = myClassTs<a, b>;
And in C++17, it would be
template <typename ... Ts>
class myClassTs : public base, public Ts...
{
public:
virtual void doRender(){
(static_cast<void>(Ts::callMe()), ...);
} override;
}
my problem is a little bit weird and I'm not able to find an answer to it.
1) I do have a nested template class for my protocol
template <template<class TMessage> class TFrame, class TMessage>
class Protocoll
{
...
}
2) I do have an implementation for my frame and message
class MessageImpl : public Message
{
...
}
class FrameImpl : public Frame<MessageImpl>
{
...
}
3) Now I want to implement my protocol using the implementations for frame and message.
class ProtocolImpl : public Protocol<FrameImpl, MessageImpl>
{
...
}
The compiler complains about the first template Parameter "FrameImpl", because it is (obviously) no generic template type any more.
Is there any possibility to make this compile?
I don't want to make my 'FrameImpl' generic/template because than I would need to implement it in the header.
Thanks a lot
Edit:
Because of requesting a complete sample:
//--------------------- definitions
class Message
{
public:
virtual ~Message() = default;
virtual void foo() noexcept = 0;
};
template <class Message>
class Frame
{
public:
virtual ~Frame() = default;
virtual void foo() noexcept = 0;
};
template <template<class TMessage> class TFrame, class TMessage>
class Protocol
{
public:
virtual ~Protocol() = default;
virtual void foo() noexcept;
};
//--------------------- implementations
class MessageImpl : public Message
{
public:
void foo() noexcept
{ }
};
class FrameImpl : public Frame<MessageImpl>
{
public:
FrameImpl()
: message{ }
{ }
void foo() noexcept
{
message.foo();
}
private:
MessageImpl message;
};
class ProtocolImpl : public Protocol<FrameImpl, MessageImpl>
{
};
in the declaration of "ProtocolImpl", I could pass Frame as template type, but not FrameImpl.
You can do
template <typename>
using FrameImplT = FrameImpl;
class ProtocolImpl : public Protocol<FrameImplT, MessageImpl>
{
// ...
};
But think at what is the purpose of those template parameters.
I have defined an interface class A which defines some basic functions. In my implementation I have a base class A0 which implements this interface and from this base class I have derived several other classes in a hierarchy.
#include <iostream>
#include <string>
class IContainer
{
public:
IContainer() {};
virtual ~IContainer() {};
virtual void loadDefaults() = 0;
virtual void storeDefaults() = 0;
virtual bool open() = 0;
virtual bool close() = 0;
};
class IContainerReader
{
public:
IContainerReader() {};
virtual ~IContainerReader() {};
virtual bool read() = 0;
};
class IContainerWriter
{
public:
IContainerWriter() {};
virtual ~IContainerWriter() {};
virtual bool write() = 0;
};
class ContainerBase : public IContainer
{
public:
ContainerBase() {}
virtual ~ContainerBase() {}
void loadDefaults() {}
void storeDefaults() {}
};
class CSVBase : public ContainerBase
{
public:
CSVBase() {}
virtual ~CSVBase() {}
void setFilename() {}
bool open() { return true; }
bool close() { return true; }
};
class CSVReader : public CSVBase, public IContainerReader
{
public:
CSVReader() {}
virtual ~CSVReader() {}
bool read() { return true; }
};
class CSVWriter : public CSVBase, public IContainerWriter
{
public:
CSVWriter() {}
virtual ~CSVWriter() {}
bool write() { return true; }
};
int main(int argc, char *argv[])
{
CSVReader r;
CSVWriter w;
IContainerReader *ir = &r;
IContainerWriter *iw = &w;
ir->open();
iw->open();
ir->read();
iw->write();
ir->close();
iw->close();
return 0;
}
As you can see I defined a IContainerReader and a IContainerWriter class which defines special functions only relevant to the respective implementation.
But now I have a problem, because I want to be sure that a Reader or a writer always has the container base as well. So the logical solution would be to derive IContainerReader/-Writer from IContainer. But when I do this, thge compiler complains, because it expects that now a Reader/Writer object implements again the base functions as well, which are already defined via the base class. But if I let IContainerReader not derive from IContainer a pointer to one of those objects is not guruanteed to have the IContainer functionality as well.
If I try to compile it like this I get errors, because IContainerReader is not a IContainer
||=== Build: Debug in CPPMingW (compiler: GNU GCC Compiler) ===|
D:\src\c\Tests\CPPMingW\main.cpp||In function 'int main(int, char**)':|
D:\src\c\Tests\CPPMingW\main.cpp|83|error: 'class IContainerReader' has no member named 'open'|
D:\src\c\Tests\CPPMingW\main.cpp|84|error: 'class IContainerWriter' has no member named 'open'|
D:\src\c\Tests\CPPMingW\main.cpp|89|error: 'class IContainerReader' has no member named 'close'|
D:\src\c\Tests\CPPMingW\main.cpp|90|error: 'class IContainerWriter' has no member named 'close'|
||=== Build failed: 4 error(s), 0 warning(s) (0 minute(s), 5 second(s)) ===|
However, if I derive IContainerReader from IContainer as it should be, I get the following errors:
||=== Build: Debug in CPPMingW (compiler: GNU GCC Compiler) ===|
D:\src\c\Tests\CPPMingW\main.cpp||In function 'int main(int, char**)':|
D:\src\c\Tests\CPPMingW\main.cpp|78|error: cannot declare variable 'r' to be of abstract type 'CSVReader'|
D:\src\c\Tests\CPPMingW\main.cpp|58|note: because the following virtual functions are pure within 'CSVReader':|
D:\src\c\Tests\CPPMingW\main.cpp|11|note: virtual void IContainer::loadDefaults()|
D:\src\c\Tests\CPPMingW\main.cpp|12|note: virtual void IContainer::storeDefaults()|
D:\src\c\Tests\CPPMingW\main.cpp|14|note: virtual bool IContainer::open()|
D:\src\c\Tests\CPPMingW\main.cpp|15|note: virtual bool IContainer::close()|
D:\src\c\Tests\CPPMingW\main.cpp|79|error: cannot declare variable 'w' to be of abstract type 'CSVWriter'|
D:\src\c\Tests\CPPMingW\main.cpp|67|note: because the following virtual functions are pure within 'CSVWriter':|
D:\src\c\Tests\CPPMingW\main.cpp|11|note: virtual void IContainer::loadDefaults()|
D:\src\c\Tests\CPPMingW\main.cpp|12|note: virtual void IContainer::storeDefaults()|
D:\src\c\Tests\CPPMingW\main.cpp|14|note: virtual bool IContainer::open()|
D:\src\c\Tests\CPPMingW\main.cpp|15|note: virtual bool IContainer::close()|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 6 second(s)) ===|
So the compiler expects me to reiplment all the functions from the base classes in the derived class as well.
So is there a solution to this, without having to define all these functions in the Reader/Writer class again? Of course I could implement dummies which just go down to the base class, but I consider this a bit clumsy and unneccessary overhead and I hope that there may be a better solution for this.
I hope I got it right. You have a kind of diamond problem. You inherit from the IContainer via two paths .
Normally in such cases you would have two instances of IContainer created per one instance of CSVReader, and the calls to IContainer methods would be ambiguous. In your case the path through IContainerReader does not have defined the mentioned functions. Virtual inheritance makes that only one instance is created.
Inheritance from IContainer should be declared as virtual. Virtual inheritance makes that every derivation from a class "will get combined together" (sorry for not very technical terms but this is how I understand it in simple english). In your case, only one copy of IContainer for both paths will be created, and the vtables will get filled from both paths.
This code compiles:
#include <iostream>
#include <string>
class IContainer
{
public:
IContainer() {};
virtual ~IContainer() {};
virtual void loadDefaults() = 0;
virtual void storeDefaults() = 0;
virtual bool open() = 0;
virtual bool close() = 0;
};
class IContainerReader : virtual public IContainer
{
public:
IContainerReader() {};
virtual ~IContainerReader() {};
virtual bool read() = 0;
};
class IContainerWriter : virtual public IContainer
{
public:
IContainerWriter() {};
virtual ~IContainerWriter() {};
virtual bool write() = 0;
};
class ContainerBase : virtual public IContainer
{
public:
ContainerBase() {}
virtual ~ContainerBase() {}
void loadDefaults() {}
void storeDefaults() {}
};
class CSVBase : public ContainerBase
{
public:
CSVBase() {}
virtual ~CSVBase() {}
void setFilename() {}
bool open() { return true; }
bool close() { return true; }
};
class CSVReader : public CSVBase, public IContainerReader
{
public:
CSVReader() {}
virtual ~CSVReader() {}
bool read() { return true; }
};
class CSVWriter : public CSVBase, public IContainerWriter
{
public:
CSVWriter() {}
virtual ~CSVWriter() {}
bool write() { return true; }
};
int main(int argc, char *argv[])
{
CSVReader r;
CSVWriter w;
IContainerReader *ir = &r;
IContainerWriter *iw = &w;
ir->open();
iw->open();
ir->read();
iw->write();
ir->close();
iw->close();
return 0;
}
I'm trying to do something like C# explicit interface implementation in unmanaged C++. I am able to do it so long as the function implementation is part of the class definition but I can't figure out how to get it to work with the function implementation in the source file.
Here's my test code:
class Base
{
public:
virtual void Func() = 0;
void CallFunc()
{
Func();
}
};
class Base1 : public Base
{
public:
virtual void Func() = 0;
};
class Base2 : public Base
{
public:
virtual void Func() = 0;
};
// This Works
class Multi : public Base1, public Base2
{
public:
virtual void Base1::Func()
{
puts("Base1::Func()");
}
virtual void Base2::Func()
{
puts("Base2::Func()");
}
};
// This does not
// 1>multipeinheritancetest.cpp(60): error C2509: 'Func' : member function not declared in 'Multi'
// 1> multipeinheritancetest.cpp(51) : see declaration of 'Multi'
// 1>multipeinheritancetest.cpp(65): error C2509: 'Func' : member function not declared in 'Multi'
// 1> multipeinheritancetest.cpp(51) : see declaration of 'Multi'
/*
class Multi : public Base1, public Base2
{
public:
virtual void Base1::Func();
virtual void Base2::Func();
};
void Multi::Base1::Func()
{
puts("Base1::Func()");
}
void Multi::Base2::Func()
{
puts("Base2::Func()");
}
*/
// This is a work-around for when I don't want to declare the full function in the header
/*
class Multi : public Base1, public Base2
{
public:
virtual void Base1::Func() { Base1_Func(); }
virtual void Base2::Func() { Base2_Func(); }
void Base1_Func();
void Base2_Func();
};
void Multi::Base1_Func()
{
puts("Base1_Func()");
}
void Multi::Base2_Func()
{
puts("Base2_Func()");
}
*/
void RunMultiTest()
{
Multi m;
m.Base1::CallFunc();
m.Base2::CallFunc();
}
Is there a way to do this and my syntax is just off or is this a Visual Studio bug or is this just not possible with C++?
The Base1::Func isn't valid in your "works" case either, it's just accepted by your compiler.
If you want two different functions call them two different names. If you want one function, use virtual inheritance:
EDIT: fixed from comment
class Base1 : public virtual Base
and
class Base2 : public virtual Base
and then remove the base qualification from the function override.