Im trying to define an interface (abstract class) which will "automatically" register any instance created to a global map, where the key is an uint8_t and the value is a pointer to the interface class.
All classes that will implement this interface already have a method to retrieve a unique id with a getId() method. I've tried the following approach, but it get warningsn when I use the (then) abstract method getId() in the c'tor and d'tor of the interface, which I can understand. But I get an error when I try to create an instance of LightZoneImpl because it has no implementation of getId().
What am I doing wrong here?
Note: This is a simplified example of the real thing, lots of other classes etc involved in the real thing.
class ILightZone; // forward
typedef std::map<uint8_t, ILightZone*> LightZoneMap;
extern LightZoneMap lightZoneMap;
/**
* #brief Interface defining a Lightzone operating node, automatically (de-)registered in the lightZoneMap
*
*/
class ILightZone {
public:
ILightZone() {
lightZoneMap[getId()] = this; // <== warning: pure virtual function called from c'tor
}
virtual ~ILightZone() {
lightZoneMap.erase(getId()); // <== warning: pure virtual function called from d'tor
}
virtual const uint8_t getId() const = 0;
virtual void setLightOn() = 0;
virtual void setLightOff() = 0;
virtual bool isLightOn() = 0;
virtual void setIntensity(const uint8_t percentage) = 0;
virtual uint8_t getIntensity() = 0;
};
class BaseNode {
public:
BaseNode(uint8_t nodeId) : nodeId(nodeId) {};
virtual ~BaseNode() {};
virtual const uint8_t getid() const { return nodeId; };
private:
uint8_t nodeId;
};
class LightZoneImpl : public ILightZone, public BaseNode {
public:
LightZoneImpl() {};
virtual ~LightZoneImpl() {};
using BaseNode::getId;
void setLightOn() override { /* implementation */};
void setLightOff() override { /* implementation */};
bool isLightOn() override { return false; };
void setIntensity(const uint8_t percentage) override { /* implementation */ };
uint8_t getIntensity() override { return 0; };
}
LightZoneImpl zone{12}; // <= error: cannot declare variable 'zone' to be of abstract type LightZoneImpl
Note2: The example below is modified to show the solution suggested below
class ILightZone; // forward
typedef std::map<uint8_t, ILightZone*> LightZoneMap;
extern LightZoneMap lightZoneMap;
/**
* #brief Interface defining a Lightzone operating node, automatically (de-)registered in the lightZoneMap
*
*/
class ILightZone {
public:
ILightZone(uint8_t nodeId) : nodeId(nodeId) {
lightZoneMap[nodeId] = this;
}
virtual ~ILightZone() {
lightZoneMap.erase(nodeId);
}
const uint8_t getId() const { return nodeId; };
virtual void setLightOn() = 0;
virtual void setLightOff() = 0;
virtual bool isLightOn() = 0;
virtual void setIntensity(const uint8_t percentage) = 0;
virtual uint8_t getIntensity() = 0;
private:
uint8_t nodeId;
};
class BaseNode {
public:
BaseNode(uint8_t nodeId) : nodeId(nodeId) {};
virtual ~BaseNode() {};
virtual const uint8_t getid() const { return nodeId; };
private:
uint8_t nodeId;
};
class LightZoneImpl : public ILightZone, public BaseNode {
public:
LightZoneImpl(uint8_t nodeId) : ILightZone(nodeId), BaseNode(nodeId) {};
virtual ~LightZoneImpl() {};
using BaseNode::getId;
void setLightOn() override { /* implementation */};
void setLightOff() override { /* implementation */};
bool isLightOn() override { return false; };
void setIntensity(const uint8_t percentage) override { /* implementation */ };
uint8_t getIntensity() override { return 0; };
}
LightZoneImpl zone{12}; // <= error: cannot declare variable 'zone' to be of abstract type LightZoneImpl
Virtual dispatch doesn't start using the derived-class function overrides until construction completes: at the time you hoped getId() would use the derived-class override, only part of the abstract base class had been constructed - the derived object didn't exist to have its functions called.
You can have derived classes or a factory function provide the id and operate on the map.
Elaboration/example as requested by Bascy...
You can think of the objects involved here as being a LightZoneImpl object in which an ILightZone base class object is embedded. To construct the LightZoneImpl, the base class must be constructed first... and while that's happening the derived-class object doesn't exist or have the invariants (guarantees about state) that the derived-class constructor sets up, so it's premature to call any derived class overrides of the virtual functions. For that reason, the C++ Standard says the base class virtual function implementations should continue to be called, but if they're unavailable because the function is pure virtual your program will terminate.
To work around this, you can do what Mooing Duck suggests in his comment, and have the derived class specify an id that the base class saves. That's probably best. You could also have a factory function that creates light zones, letting the derived-class constructor pass it down to the base class for storage/use:
std::unique_ptr<LightZoneImpl> lz_factory() {
static int id_ = 0;
if (id_ > 255)
throw std::runtime_error("too many lightzones");
return std::make_unique<LightZoneImpl>(id_++);
}
You'd then want to make the light zone constructors private and make the factory a friend.
Related
I have got myself into a strange issue now. Ill write a really simplified version of the same.
class Base
{
public:
virtual int func1()=0;
virtual int func2()=0;
protected:
int n;
};
class der1: public Base
{
// implements the virtual functions of the base and uses the protected data
// members of the base.
};
class der2: public Base
{
// implements the virtual functions of the base and uses the protected data
// members of the base.
}
Now the problem.... both der1 and der2 implements the virtual functions of base pretty much the same way. But some other classes (der3, der4) has their own implementations. But still need to inherit from base.
How do i refactor the code to remove the code duplication in an oop manner?
Here's one solution using an intermediate layer of another abstract base class:
class Base12 : public Base {
protected:
int commonFuncStuffA() {
// Commonly used stuff
}
int commonFuncStuffB() {
}
};
class der1: public Base12
{
public:
virtual int func1() {
n = commonFuncStuffA();
}
virtual int func2() {
n = somethingElse;
}
};
class der2: public Base12
{
public:
virtual int func1() {
n = commonFuncStuffA();
}
virtual int func2() {
n = commonFuncStuffB();
}
};
What I'd do for real production code design looks a bit different though.
Declare an interface for the pure virtual functions
struct IMyInterface {
virtual int func1() = 0;
virtual int func2() = 0;
virtual ~IMyInterface {}
};
Provide a abstract base class with the commonly used data members and functions
class BaseImpl : public IMyInterface {
protected:
int n;
int commonFuncStuffA() {
// Commonly used stuff
}
int commonFuncStuffB() {
// Commonly used stuff
}
};
Provide implementations of the interface in the finally derived classes
class der1: public BaseImpl {
public:
virtual int func1() {
n = commonFuncStuffA();
}
virtual int func2() {
n = somethingElse;
}
};
class der2: public BaseImpl {
public:
virtual int func1() {
n = commonFuncStuffA();
}
virtual int func2() {
n = commonFuncStuffB();
}
};
class der3: public IMyInterface {
public:
virtual int func1() {
// Some completely different implementation of the interface
}
virtual int func2() {
// Some completely different implementation of the interface
}
};
class der4: public IMyInterface {
public:
virtual int func1() {
// Some completely different implementation of the interface
}
virtual int func2() {
// Some completely different implementation of the interface
}
};
Option 1
You may consider using your most common implementation in the Base class. The main feature or drawback of this method is that the base class would no longer be abstract. If this is a problem, go to option 2.
Maybe you can even cope with differences in the derived classes by using the template method pattern to extract the differences in protected virtual functions invoked by the template method.
In anyway, for derived classes that need a completely different appoach, you'd just override the the Base class' method.
class Base
{
public:
virtual int func1();
virtual int func2()=0;
protected:
virtual void f1_specific_part1()=0;
virtual void f1_specific_part2()=0;
int n;
};
int Base::func1() { // common skeleton of the algorithm
...
f1_specific_part1();
...
f1_specific_part2();
...
}
class Der1: public Base
{
protected:
void f1_specific_part1() override; // Implements the specific variation
virtual void f1_specific_part2() override;
};
Option 2
You may consider to factorize the common code of the derived classes into a protected method of the Base class.
The override of the pure virtual function would then just call the base class protected common function (for der1 and der2) or just use their own implementation that is completely different (for der3 and der4).
class Base
{
public:
virtual int func1()=0;
virtual int func2()=0;
protected:
int common_part1_funct1(); // implements some common parts
int common_part2_funct1();
int n;
};
class Der1: public Base
{
...
int func1() override {
common_part1_funct1();
...
common_part2_funct1();
...
}
};
Option 3 ?
Important remark: My answer assumes that there are many commonalities between most of the derived classes. However if you have only a small subset of derived classes that share some commonalities, then the answer of Evg would be would be more appropriate.
The idea with Base12 is:
struct Base {
virtual int func1() = 0;
virtual int func2() = 0;
};
struct Base12 : Base {
protected:
int func12();
};
struct Der1: public Base12 {
virtual int func1() {
return func12();
virtual int func2() {
return func12();
};
struct Der2: public Base12 {
virtual int func1() {
return func12();
virtual int func2() {
return func12();
};
Why I can't create new instance of class which is derived class of my abstract base class? My derived class has overriden base method but with different parametr which is derived class of base class param.
class BaseArg {
} ;
class DerivedArg :public BaseArg{
} ;
class BaseHandler{
public:
virtual void handle(BaseArg* arg) = 0;
} ;
DerivedHandler {
void handle(DerivedArg* arg) {}
} ;
auto x = new DerivedHandler() ;
Compiler returns "Cannot Instantiate abstract class"
Why? In my opinion it should works.
class BaseHandler
{
public:
virtual void handle(BaseArg* arg) = 0;
};
You declare a virtual function handle that needs to be able to accept any kind of BaseArg.
class DerivedHandler : public BaseHandler
{
public:
void handle(DerivedArg* arg) { }
};
Your overriding function just accepts one specific type of BaseArg, so it does not suffice to provide an implementation for the (more general!) inherited function handle. The other way round would have worked (in theory only, see below) – or it would have (truely) worked with return type, as a DerivedArg returned always is a BaseArg, too...
For overview:
class Base
{
public:
virtual void f0(BaseArg* arg) = 0;
virtual void f1(DerivedArg* arg) = 0;
virtual BaseArg* f2() = 0;
virtual DerivedArg* f3() = 0;
};
class Derived : public Base
{
public:
virtual void f0(DerivedArg* arg) override; // FAILS!
virtual void f1(BaseArg* arg) override; // (fine...)(*)
virtual DerivedArg* f2() override; // fine...
virtual BaseArg* f3() override; // FAILS!
};
(*) Actually, this case would have been fine in theory. C++, however, does not support contravariant function arguments, so this case will fail, too (the new function considered being an overload only)!
For more information, have a look at Wikipedia.
When trying to call a method setCurrentState Im getting the error:
StateMachine<Cow>::setCurrentState(std::shared_ptr<State<Cow>>)':
cannot convert argument 1 from 'std::shared_ptr<ChaseState>' to
'std::shared_ptr<State<Cow>>'
This indicates that a std::shared_ptr<ChaseState> is not a std::shared_ptr<State<Cow>> but why is it not?
The call to the function:
std::shared_ptr<ChaseState> initialState = std::make_shared<ChaseState>();
m_stateMachine->setCurrentState(initialState);
State.h
#pragma once
template <class entity_type>
class State
{
public:
virtual void enter(entity_type*) = 0;
virtual void execute(entity_type*) = 0;
virtual void exit(entity_type*) = 0;
};
ChaseState.h
class Cow;
class ChaseState : State<Cow>
{
public:
ChaseState();
// Inherited via State
virtual void enter(Cow*) override;
virtual void execute(Cow*) override;
virtual void exit(Cow*) override;
};
In my StateMachine I have private variable:
std::shared_ptr<State<entity_type>> m_currentState;
and the setCurrentState function:
void setCurrentState(std::shared_ptr<State<entity_type>> s) { m_currentState = s; }
As I understand the derived class ChaseState is a State (behause it inherits from state).
You need to declare your inheritance public. Class inheritance is private by default, meaning that you cannot cast from Derived to Base because the inheritance is not recognized outside of the class itself (same as how private members cannot be accessed outside the class).
To fix, make your inheritance public:
class ChaseState : public State<Cow>
// ^^^^^^
I would to block child classes from overriding a base method and have the child classes override a new method in a parental class. In other words, a child class of the base class blocks the base class methods and delegates to a new method that further child classes must override. I still want the base class method to be available.
Here is an example:
#include <iostream>
#include <string>
struct Base
{
virtual const std::string& class_name(void) = 0;
};
struct Level1
: public Base
{
private: // Prevent child classes from overriding
// the Base::class_name method
const std::string& class_name(void)
{
static std::string name;
name = "class" + class_name_from_level_1();
return name;
}
protected:
// This is the "new" or redirected class that child classes
// must override.
virtual const std::string& class_name_from_level_1(void) = 0;
};
struct Level2
: public Level1
{
static std::string name;
const std::string& class_name_from_level_1(void)
{
if (name.length() == 0)
{
name = "Level2";
}
return name;
}
};
int main(void)
{
Level2 lev2;
std::cout << lev2.class_name() << "\n";
return 0;
}
I am getting the following errors from g++:
$ g++ hiding_virt_methods.cpp -o hiding_virt_methods.exe
hiding_virt_methods.cpp: In function `int main()':
hiding_virt_methods.cpp:15: error: `virtual const std::string& Level1::class_name()' is private
hiding_virt_methods.cpp:43: error: within this context
In the above example, I want the following chain of execution for Level2:
Base::class_name() --> Level1::class_name_from_level_1() --> Level2::class_name_from_level_1()
Also, I only want to block inheritance of specific methods in the Base class. Protected and Private Inheritance affect all the public methods.
So how do I stop the chain of inheritance of specific Base methods at different levels in the inheritance tree?
Edit: Real world example.
I have an interface class Record. Class Record_With_Id inherits from class Record and adds an ID field. The class Record contains an accept_visitor method. Class Record_With_Id overrides accept_visitor to apply to the ID field, then calls a virtual method, record_with_id_accept_visitor, which descendants must implement.
For your immediate problem, you can rename your class_name() functions to class_name_impl() or similar, then in the base class have a class_name() function that calls the implementation one. That way, only the base class version will match when calling class_name() on a derived object.
More generally, you can frustrate attempts to call the base class methods by having same-named functions in the derived classes - as you've done, but anyone can cast to a Base& and call whatever they like. You can't stop virtual methods being overridable in derived classes... you can only frustrate their use.
It's worth remembering that a publicly derived class IS an instance of the base class, and SHOULD provide the base class's interface.
EDIT: re yout "real world example" edit, can you explain the problem with a normal implementation ala...
#include <iostream>
struct Visitor
{
virtual void operator()(int&) const = 0;
};
struct X
{
virtual void visit(Visitor& v) { v(a); v(b); }
int a;
int b;
};
struct X_with_C : X
{
int c;
virtual void visit(Visitor& v) { X::visit(v); v(c); }
};
struct My_Visitor : Visitor
{
void operator()(int& n) const { std::cout << ++n << '\n'; }
};
int main()
{
X x;
x.a = 10;
x.b = 20;
My_Visitor visitor;
x.visit(visitor);
X_with_C xc;
xc.a = -10;
xc.b = -20;
xc.c = -30;
xc.visit(visitor);
X& rx = xc;
rx.visit(visitor);
}
Output:
11
21
-9
-19
-29
-8
-18
-28
hasn't C++11 added final and override?
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final
Four years later, let me add that C++11 has introduced keyword final:
class Base final {
This can also be applied on the virtual methods:
class Base{
protected:
virtual void doWork() = 0;
public:
virtual void startWork() final { doWork(); }
};
class Derived: public Base{
protected:
virtual void doWork() override { /* some work */ }
public:
// error: overriding final function ‘virtual void Base::startWork()’
virtual void startWork() override { /* something else */ }
};
Visual Studio 2005 and above implement a keyword "sealed", which is a Microsoft extension to C++. You put it in the declaration of Level1::class_name(). I don't think there is a portable way.
It appears that you're trying to do something in a way that's hard.
Depending on what it is that you're trying to achieve, the following may be a solution.
#include <iostream>
#include <string>
struct Base
{
virtual std::string class_name() const = 0;
};
class Level1
: public Base
{
public:
std::string class_description() const
{
return "class " + class_name();
}
};
class Level2
: public Level1
{
public:
virtual std::string class_name() const
{
return "Level2";
}
};
int main()
{
Level2 lev2;
std::cout << lev2.class_description() << "\n";
}
In the above code I've assumed it's for debugging/tracing or something like that. For id purposes look into typeid (a built-in operator).
Cheers & hth.,
I'm working on a plugin framework, which supports multiple variants of a base plugin class CPlugin : IPlugin. I am using a boost::shared_ptr<IPlugin> for all reference to the plugins, except when a subsystem needs the plugin type's specific interface. I also need the ability to clone a plugin into another seprate object. This must return a PluginPtr. This is why CPlugin is a template rather than a straight class. CPlugin::Clone() is where the template paramter is used. The following are the class definitions I am using:
IPlugin.h
#include "PluginMgr.h"
class IPlugin;
typedef boost::shared_ptr<IPlugin> PluginPtr;
class IPlugin
{
public:
virtual PluginPtr Clone() =0;
virtual TYPE Type() const =0;
virtual CStdString Uuid() const =0;
virtual CStdString Parent() const =0;
virtual CStdString Name() const =0;
virtual bool Disabled() const =0;
private:
friend class CPluginMgr;
virtual void Enable() =0;
virtual void Disable() =0;
};
CPlugin.h
#include "IPlugin.h"
template<typename Derived>
class CPlugin : public IPlugin
{
public:
CPlugin(const PluginProps &props);
CPlugin(const CPlugin&);
virtual ~CPlugin();
PluginPtr Clone();
TYPE Type() const { return m_type; }
CStdString Uuid() const { return m_uuid; }
CStdString Parent() const { return m_guid_parent; }
CStdString Name() const { return m_strName; }
bool Disabled() const { return m_disabled; }
private:
void Enable() { m_disabled = false; }
void Disable() { m_disabled = true; }
TYPE m_type;
CStdString m_uuid;
CStdString m_uuid_parent;
bool m_disabled;
};
template<typename Derived>
PluginPtr CPlugin<Derived>::Clone()
{
PluginPtr plugin(new Derived(dynamic_cast<Derived&>(*this)));
return plugin;
}
An example concrete class CAudioDSP.h
#include "Plugin.h"
class CAudioDSP : CPlugin<CAudioDSP>
{
CAudioDSP(const PluginProps &props);
bool DoSomethingTypeSpecific();
<..snip..>
};
My problem (finally) is that CPluginMgr needs to update m_disabled of the concrete class, however as it is passed a PluginPtr it has no way to determine the type and behave differently according to the template paramater. I can't see how to avoid declaring ::Enable() and ::Disable() as private members of IPlugin instead but this instantly means that every section of the application now needs to know about the CPluginMgr class, as it is declared as a friend in the header. Circular dependancy hell ensues. I see another option, declare the Enable/Disable functions as private members of CPlugin and use boost::dynamic_pointer_cast<CVariantName> instead.
void CPluginMgr::EnablePlugin(PluginPtr plugin)
{
if(plugin->Type == PLUGIN_DSPAUDIO)
{
boost::shared_ptr<CAudioDSP> dsp = boost::dynamic_pointer_cast<CAudioDSP>(plugin);
dsp->Enable();
}
}
This however leads to lots of duplicate code with many multiple variants of the base CPlugin template. If anyone has a better suggestion please share it!
You can easily write :
class CPluginMgr;
class IPlugIn ..
{
friend CPluginMgr;
...
};
Only a predefinition is needed for friend.
I think your get in trouble trying to return a shared_ptr in clone method. Why don't you make use of covariant return types? What you are doing is a common idiom called Virtual Constructor.
class IPlugin
{
public:
virtual IPlugin* clone() = 0;
// ...
}
class CPluginMgr;
class CPlugin : public IPlugin
{
public:
virtual CPlugin* clone() = 0;
friend CPluginMgr; // as #Christopher pointed out
void Enable(bool enable) { m_disabled = !enable; }
// ...
}
class CAudioDSP : public CPlugin
{
public:
virtual CAudioDSP* clone();
// ...
}
CAudioDSP* CAudioDSP::clone()
{
return new CAudioDSP(*this); // assume copy constructors are properly implemented
}
Returning a shared_ptr may lead you to make errors (as early destruction of temparary objects) and I think is not usually a good idea.