This is Parent Class Foo, and It is abstract(virtual).
And Foo class' methods are declared in Foo.cpp.
[Foo.h]
class Foo
{
public:
Foo();
~Foo();
virtual void methodA(int no, const char* path) = 0;
virtual void methodB(const char* name, const char* path) = 0;
virtual void methodC(const char* name, const char* path) = 0;
// ... more 20 virtual methods
}
[Foo.cpp]
Foo::Foo(){}
Foo::~Foo(){}
Foo::methodA(int no, const char* path)
{
// do something
}
Foo::methodB(const char* name, const char* path)
{
// do something
}
Foo::methodC(const char* name, const char* path)
{
// do something
}
// ... more 20 methods
In Foo class, methodA must be called with parameter no.
And Also parameter no must increase sequentially from 0.
It is very uncomfortable. So I want to override methodA in child class Bar.
Bar class has a memeber variable m_no and methodA without parameter no.
And m_no will increase when methodA called.
This is my code.
[Bar.h]
class Bar : public Foo
{
public:
Bar();
~Bar();
void methodA(const char* path);
private:
int m_no;
}
[Bar.cpp]
Bar::Bar() : m_no(0) {}
Bar::~Bar() {};
Bar::methodA(const char* path)
{
Foo::methodA(m_no++, path);
}
But class Bar is abstract(virtual), because class Bar isn't declare virtual methods (methodA, methodB, methodC and 20 methods more).
So, I edited.
[Bar.h]
class Bar : public Foo
{
public:
Bar();
~Bar();
void methodA(const char* path);
void methodB(const char* name, const char* path);
void methodC(const char* name, const char* path);
// ... more 20 methods
private:
int m_no;
}
[Bar.cpp]
Bar::Bar() : m_no(0) {}
Bar::~Bar() {};
Bar::methodA(const char* path)
{
methodA(m_no++, path);
}
Bar::methodA(int no, const char* path)
{
Foo::methodA(no, path);
}
Bar::methodB(const char* name, const char* path)
{
Foo::methodB(name, path);
}
Bar::methodC(const char* name, const char* path)
{
Foo::methodC(name, path);
}
// ... more 20 methods
How can I inherit class Foo without declare all virtual methods?
How can I inherit class Foo without declare all virtual methods?
You provide an implementation for them.
(note: this part adds to #TommyA's answer, but it is too long for a comment; see second part, for a different approach)
consider:
class Foo
{
public:
Foo();
virtual ~Foo() = 0; // this is the only pure virtual function
virtual void methodA(int no, const char* path);
virtual void methodB(const char* name, const char* path);
virtual void methodC(const char* name, const char* path);
// ... more 20 virtual methods
}
Foo.cpp:
Foo::~Foo() = default; // unless you need to add some impleemntation
// other methods implemented like you did
Bar:
class Bar : public Foo
{
public:
Bar();
virtual ~Bar();
void methodA(const char* path);
// do not implement anything of Foo here (it is inherited already)
private:
int m_no;
}
Second part
Another approach would be to follow the open-closed principle (decide that if the method must be called with an ever increasing number, then it is the responsibility of Foo to implement that, and add a template method implementation):
class Foo
{
public:
// public interface for methodA, accessible to clients
void methodA(const char* path);
protected:
virtual void methodA_impl(int no, const char* path) = 0;
private:
int m_no; // private: not accesible to specializations
};
void Foo::methodA(const char* path)
{
methodA_impl(m_no++, path);
}
class Bar: public Foo
{
// ...
protected:
void methodA_impl(int no, const char* path) override;
}
void Bar::methodA_impl(int no, const char* path)
{
// Bar-speciffic implementation here
}
This follows the open-closed principle because the "number must be incremented at every call" requirement is fixed and cannot be overriden by
specializations.
Clients of Foo specializations cannot change how methodA_impl is called (it is always called correctly) and you have the virtual method behavior you need.
When a base class is pure virtual the child class that you wish to instantiate needs to fully implement the pure virtual methods before you can instantiate it. But you could make a "middle" layer that default implemented the methods, that you then inherited from.
Note: Remember to use virtual destructors creating non-final classes.
The whole point of that class Foo is that has been defined so all derived classes must override all the pure virtual methods.
The most obvious workaround is to complain bitterly to whoever provided class Foo and get them to provide a sensibly designed base class. It is absolutely lousy design to define a class that way, unless it is obvious that ALL virtual functions MUST be overridden. It is also lousy design (because there are circumstances where the result is undefined behaviour) to have a base class that does not have a virtual destructor.
If this is your design, redesign your entire class hierarchy. Seriously, the design is that bad.
However, it is possible to simply derive another class from Foo and override all member functions necessary. For example;
class FooIntermediary : public Foo
{
virtual void methodA(int no, const char* path);
virtual void methodB(const char* name, const char* path);
virtual void methodC(const char* name, const char* path);
};
void FooIntermediary::methodA(int no, const char *path)
{
Foo::methodA(no, path);
}
void FooIntermediary::methodB(const char *name, const char *path)
{
Foo::methodB(name, path);
}
// etc
Then any classes derived from FooIntermediary will only be forced to override any inherited functions from Foo that FooIntermediary has not overridden.
You could find another class, derived from Foo, that can be instantiated, and has (apart from the particular change you seek) all the behaviour your need. By definition, that class will have overridden all of the inherited abstract functions. So derive a class from it, and override only the virtual function you need to.
Related
I have a base Write class that has a pure virtual function write (std::string text) that requires all derived classes to implement it. In the base class, there is an overloaded write function that takes in an int and calls the pure virtual write().
In the derived class, we implement the write (std::string text), as required.
In the main, I'm able to call console.write("dog\n");, but I'm not able to call it with the overloaded version that takes in an int without going through the base class name Write. Is there anyway to define this inheritance so that both write functions, one that takes in a std::string and one that takes in an int without giving away the details of the inheritance by going through the Write class name, as shown on the last line of the program?
I don't want the user to be able to call the overloaded write(int)' through theWrite` class name, if possible.
#include <iostream>
class Write
{
protected:
virtual void write (const std::string &text) = 0;
public:
void write (const int &number)
{
write (std::to_string (number));
}
};
class Console_Write : public Write
{
public:
void write (const std::string &text) override
{
std::cout << text;
}
};
int main()
{
Console_Write console;
console.write("dog\n");
console.Write::write (1); // Is it possible to be able to change the inheritance so we can just call: console.write (1);
}
The normal pattern for this would be having your base class look something like:
class Write {
public:
virtual ~Write() = default;
void write(const std::string& str) {
write_internal(str);
}
void write(int n) {
write(std::to_string(n));
}
private:
virtual void write_internal(const std::string& str) = 0;
}
class ConsoleWrite : public Write {
public:
~ConsoleWrite() = default;
private:
void write_internal(const std::string& str) {
std::cout << str;
}
}
The pattern even has a name "Non-Virtual Interface" - https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface has more information about the pattern.
I did a small exemple to try to explain you with my poor english what I want to do :).
I have a main class who is my engine. This is my parent class of several children.
this is the parent class :
#include <string>
#include <iostream>
#include <vector>
template <typename Type>
class A
{
public:
A(std::string const &str)
: m_str(str)
{
}
void run(void) const {
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++) {
if(m_str == ACTIONS[i].key) {
return ((*(this).*ACTIONS[i].f)(m_str));
}
}
}
protected:
typedef struct s_action {
std::string key;
void (Type::*f)(std::string const &);
} t_action;
static t_action const ACTIONS[];
std::string m_str;
};
class B : public A<B>
{
public:
B(std::string const &str);
protected:
static t_action const ACTIONS[];
void error(std::string const &str);
void success(std::string const &str);
};
I would like to call children method with table pointer of member function in this parent class A::run as you can see above
This code does not compile.
I know it's not possible to have a static variable virtual, but it's
exactly that I need to do have for A::ACTIONS. I absolutely need to initialise B::ACTIONS to A::run works.
In first Is it possible? Have you got a small exemple of this case?
This is the end of my small code :
#include "Class.hpp"
B::t_action const B::ACTIONS[] = {
{"ERROR", &B::error},
{"SUCCESS", &B::success},
{"", nullptr}
};
B::B(std::string const &str)
: A<B>(str)
{
}
void B::error(std::string const &str) {
std::cerr << str << std::endl;
}
void B::success(std::string const &str) {
std::cout << str <<std::endl;
}
And the main:
#include "Class.hpp"
int main() {
B b("SUCCESS");
b.run();
return (0);
}
I didn't try, normally this code should Display SUCCESS on stdout
Thank you for your help
void run(void) const
{
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++)
if (m_str == ACTIONS[i].key)
return ((*(this).*ACTIONS[i].f)(m_str));
}
There are multiple reasons why this fails to compile. Not one, but several reasons. This entire dispatching mechanism must be completely redesigned.
The first order of business is that this is a
void run(void) const
A const class method.
The method pointer in question is:
void (Type::*f)(std::string const &);
The method pointer is not const, but mutable. From an existing const class method, you can only invoke other const methods. You cannot invoke non-const methods, either directly or indirectly via a method pointer, from a const class methods.
So the first order of business is to change this to
void (Type::*f)(std::string const &) const;
This also means that all your methods, in the child class, error() and success(), must also be const class methods too.
If it's necessary to use this dispatch mechanism with non-const methods, the run() method cannot be a const class method itself. But this is not the only problem here, so I'll continue with the const method, at hand.
return ((*(this).*ACTIONS[i].f)(m_str));
The this here, is a A<Type>. This is a method of that class. That's what this is here.
The method pointer, f is pointer to a method of Type, not A<Type>. Type is a subclass of A<Type>, and you cannot convert a pointer or a reference to a base class to a pointer or a reference to a subclass, any more than you can take a pointer to A, and convert to a pointer to B when B inherits from A. C++ does not work this way.
The solution is simple, and requires only a few small tweaks. This run() should take a reference to const Type &, and invoke the method via the passed-in reference, then a replacement abstract run() method invokes it, passing *this as a parameter:
public:
virtual void run()=0;
protected:
void run_me(const Type &me) const
{
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++)
if (m_str == ACTIONS[i].key)
return ((me.*ACTIONS[i].f)(m_str));
}
Then, each subclass that inherits this template only needs to implement a simple facade:
class B : public A<B>
{
public:
void run() const override
{
run_me(*this);
}
EDIT: This addresses the compilation error, but additional work is needed to deal with the fact that static class members cannot be overridden. The solution is also pretty simple: also leverage virtual class methods in order to implement this.
Remove the declaration of ACTIONS from the template base class, and replace it with an abstract function:
virtual const t_action *get_actions() const=0;
And use it in run_me():
const t_action *ACTIONS=this->get_actions();
The rest of run_me() remains as is, and then implement get_actions() in the child class:
const t_action *get_actions() const override
{
return ACTIONS;
}
Pretty much everything else remains the same.
The problem is that A will always use is own defined set of actions, not B's.
You don't need to create A at all, as you want to use B methods and list of methods.
Let's say that you create first a run call function:
template<typename T>
void run(T* obj, const std::string method)
{
const auto& available_methods = obj->get_methods();
auto iter = available_methods.find(method);
if(iter == available_methods.end())
{
// Handle this case
}
std::invoke(iter->second, obj); //C++17, or (obj->*(iter->second))();
}
Now for the class B, you need something very simple:
class B
{
public:
typedef std::unordered_map<std::string, void(B::*)()> MethodMap;
void foo();
static MethodMap& get_methods()
{
static MethodMap map{{"foo", &B::foo}};
return map;
}
};
Populate the map with get_methods() in the static function, and then call run through:
int main()
{
B b;
run(&b, "foo");
}
If you are going to use CRTP, IMO you need to google for CRTP first.
By the way here's a quick direct ans 2 your q:
template<typename crtp_child>
class crtp_base{
using crtp_target=crtp_child;
auto crtp_this(){
return static_cast<crtp_target*>(this);
};
auto crtp_this() const {
return static_cast<crtp_target const*>(this);
};
public:
void run(){
auto range=crtp_this()->actions.equal_range(m_str);
for(auto entry:range)
(crtp_this()->*(entry.second))(m_str);
};
protected:
crtp_base(std::string str):
m_str(str)
{};
std::string m_str;
//...
};
struct crtp_user:
crtp_base<crtp_user>
{
using crtp_base::crtp_base;//ctor fwding
protected:
friend class crtp_base<crtp_user>;
std::unordered_multimap<std::string, void (crtp_user::*)(std::string)> actions;
//...
};
I was very surprised just now to see that this code (paraphrased) built.
class Foo
{
protected:
virtual bool CheckThis(int id);
}
class Bar : public Foo
{
protected:
virtual tErrorCode CheckThis(int id, char something);
};
I thought it was not possible to override a function with a different return type? Somehow this built. OS is vxworks.
In fact, this method:
virtual tErrorCode CheckThis(int id, char something);
Does not override anything, because it has a different signature from this method:
virtual bool CheckThis(int id);
Note, that you might use the override specifier to ensure that the method in the derived class actually overrides the method of the base class.
So, this piece of code:
class Foo {
protected:
virtual bool CheckThis(int id);
};
class Bar : public Foo
{
protected:
virtual tErrorCode CheckThis(int id, char something) override;
};
Will not compile, but this one will:
class Foo {
protected:
virtual bool CheckThis(int id);
};
class Bar : public Foo
{
protected:
virtual bool CheckThis(int id) override;
};
I thought it was not possible to override a function with a different return type?
Yes, it is possible, but with some constraints.
In particular, you can't use any type you want, only a covariant type can be used.
In addition, the argument types must be the same, otherwise it is not an override.
Example:
class type1 {};
class type2 : public type1 {};
class Foo {
protected:
virtual type1& CheckThis(int id);
}
class Bar : public Foo
{
protected:
// This is not an override, it is an overload.
virtual type2& CheckThis(int id, char);
// This is an override.
virtual type2& CheckThis(int id);
};
Since C++11, you should use the special override keyword. It allows the compiler to check if the base class has a method for the derived class to override.
Live example
class Foo
{
protected:
virtual bool CheckThis(int id);
}
class Bar : public Foo
{
protected:
tErrorCode CheckThis(int id, char something) override; // error: marked 'override', but does not override
};
Moreover, since you override a base class method, the virtual keyword is not required in the derived class. The base method is virtual, so the overriding method is implicitly virtual.
Given the following code example, why is the overloaded AbstractBaseClass::DoAThing( const char* ) not visible as an inherited method in the SomeEndClass that implements the overloaded pure abstract DoAThing( const char* const* ) method?
class AbstractBaseClass
{
public:
virtual void DoAThing( const char* withThis ) {}
virtual void DoAThing( const char* const* withThat ) = 0;
AbstractBaseClass() {}
virtual ~AbstractBaseClass() {}
};
class SomeMiddlewareClass : public AbstractBaseClass
{
public:
void ThisIsCool() {}
SomeMiddlewareClass() {}
virtual ~SomeMiddlewareClass() {}
};
class SomeEndClass : public SomeMiddlewareClass
{
public:
void DoAThing( const char* const* withThat ) {}
SomeEndClass() {}
virtual ~SomeEndClass() {}
};
void SomeFunction()
{
SomeEndClass* myClass = new SomeEndClass();
myClass->DoAThing( "withThis" );
((SomeMiddlewareClass*)myClass)->DoAThing( "withThisToo" );
delete myClass;
}
The compiler (and indexer) produce the following error on the myClass->DoAThing( "withThis" ); line while the ((SomeMiddlewareClass*)myClass)->DoAThing( "withThisToo" ); line is accepted.
Invalid arguments ' Candidates are: void DoAThing(const char * const *)
no matching function for call to ‘SomeEndClass::DoAThing(const char [9])’
Shouldn't the SomeEndClass inherit the AbstractBaseClass::DoAThing( const char* ) implementation? What am I doing wrong?
Your SomeEndClass::DoAThing() function not only overrides the function inherited from the base class, but also hides the other overloads of that function in the base class.
You could add a using declaration to your SomeEndClass class:
using SomeMiddlewareClass::DoAThing;
Therefore:
class SomeEndClass : public SomeMiddlewareClass
{
public:
using SomeMiddlewareClass::DoAThing;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
void DoAThing( const char* const* withThat ) {}
SomeEndClass() {}
virtual ~SomeEndClass() {}
};
With this fix, you can see your program compiling in this live example.
In your base class DoAThing is not just virtual, but overloaded.
The function in the derived class overrides one of those overloads and hides the other.
You're then trying to call the other, which is hidden.
You can make the hidden function visible in the derived class with a using declaration:
using Base::DoAThing;
...but whether you should is a separate (more complex) question.
I have an existing project with the following class inheritance
class Base
{
public:
Base();
virtual ~Base();
void SetID(unsigned short);
virtual inline unsigned short GetID();
protected:
unsigned short id;
};
class Generic : public Base {
public:
Generic(const char *in_name);
const char* GetName() { return name; }
protected:
char name[30];
};
class Actor : public Generic
{
public:
Actor(const char *in_name);
~Actor();
void DoSomething(const char* str);
};
Now i created a separate project were i want to provide an interface that has to be implemented in order to use the functionality - i plan on reusing this project for other implementation.
class MyInterface
{
public:
virtual ~MyInterface() {}
// Our methods that need to implemented
virtual const char* GetName() = 0;
virtual void DoSomething(const char* str) = 0;
virtual unsigned short GetID() = 0;
};
Now i simply wanted to use this with my actor class e.g.
class Actor : public Generic, public MyInterface
however it fails to compile
'const char *MyInterface::GetName(void)' : is abstract see declaration of 'MyInterface::GetName'
'unsigned short MyInterface::GetID(void)' : is abstract see declaration of 'MyInterface::GetID'
error C2385: ambiguous access of 'GetName'
could be the 'GetName' in base 'Generic'
or could be the 'GetName' in base 'MyInterface'
The problem is probably that GetName is already implemented in Generic, and GetID is already implemented in Base - so in the child class Actor implementing the Interface is not possible because the compiler is not smart enough to realize there is already an implementation of these methods.
However, i found a workaround - but for this i would have to extend the header of the actor class which is not a nice thing - and i wanted to know if there is another approach - my fix is
class Actor : public Generic, public MyInterface
{
public:
Actor(const char *in_name);
~Actor();
void DoSomething(const char* str);
const char* GetName() { return Generic::GetName(); };
inline unsigned short GetID() { return Base::GetID(); };
};
Now this obviously will not work for varargs methods and i would have to implement existing methods and delegate to the parent again - is there a better solution?
EDIT For clarifications - the classes base,generic and actor exist in another project managed by others, modifications to these should be very limited. - I created a seperate project which creates a static LIB - to use functions of these in conjunction with the actor class - i created an interface to not have any dependency in my own project and also provide a reusable lib for other projects which would simply just need to implement this interface.
class Base
{
protected:
unsigned short id;
public:
void SetID(unsigned short);
virtual inline unsigned short GetID() { return id; }
virtual ~Base() {}
Base(): id() {}
};
class Generic
: public Base
{
protected:
char name[30];
public:
const char* GetName() { return name; }
Generic(const char* in_name): name() {}
};
class Actor
: public Generic
{
public:
void DoSomething(const char* str) {}
~Actor() {}
Actor(const char* in_name)
: Generic( name )
{}
};
class MyInterface
{
public:
// Our methods that need to implemented
virtual const char* name() const = 0;
virtual int id() const = 0;
virtual void doSomething( const char* str ) = 0;
virtual ~MyInterface() {}
};
template< class TpBase >
class MyInterfaceOn
: public virtual MyInterface
, public TpBase
{
public:
typedef TpBase Base;
private:
MyInterfaceOn& mutableSelf() const
{ return *const_cast<MyInterfaceOn*>( this ); }
public:
const char* name() const { return mutableSelf().Base::GetName(); }
int id() const { return mutableSelf().Base::GetID(); }
void doSomething(const char* str) { Base::DoSomething( str ); }
MyInterfaceOn( char const name[] )
: Base( name )
{}
};
class MyActor
: public MyInterfaceOn< Actor >
{
public:
MyActor( char const name[] )
: MyInterfaceOn< Actor >( name )
{}
};
int main()
{
MyInterface const& actor = MyActor( "NN" );
}