I got an Abstract Baseclass which looks like this:
class AbstractClass {
public:
virtual ~AbstractClass() = 0 {}
std::string GetName() const { return m_Name; }
private:
std::string m_Name;
};
Now I got many derived Classes and I want to implement them like this
class DerivedClass1 : public AbstractClass{
public:
DerivedClass1() = default;
~DerivedClass1() = default;
private:
std::string m_Name = "DerivedClass1";
};
int main() {
DerivedClass1 class1;
std::cout << class1.GetName();
return 0;
}
I dont want to override GetName() everytime i derive a Class, is this possible?
Edit:
I got a Linker Error. Error LNK2019.
Use only one name, in the base class, and a constructor with a parameter:
class AbstractClass{
public:
AbstractClass(const std::string& name) : m_Name(name){}
std::string GetName() const { return m_Name; }
private:
std::string m_Name;
};
DerivedClass1 : public AbstractClass{
public:
DerivedClass() : AbstractClass("DerivedClass1") {}
};
int main(){
DerivedClass1 class1;
std::cout << class1.GetName();
return 0;
}
There seems to be no reason for making the base class abstract, but if you do need that, even a pure virtual destructor must have a definition, or you will get a linker error, because it's needed when destroying derived objects.
Also, if the destructor didn't exist, when would m_Name be destroyed?
class Abstract
{
public:
virtual ~Abstract() = 0;
};
Abstract::~Abstract() {}
This makes a class that can't be instantiated, but whose derived classes can still be destroyed.
That's not how you "override" GetName(). You can either make GetName() virtual and override it in your derived classes:
class AbstractClass {
public:
virtual ~AbstractClass() = default;
virtual std::string GetName() const { return "AbstractClass"; }
private:
std::string m_Name;
};
and:
class DerivedClass1 : public AbstractClass {
public:
DerivedClass() = default;
std::string GetName() const override { return "DerivedClass1"; }
};
Or you can set m_Name in your derived classes by passing it to the base class constructor:
class AbstractClass {
public:
AbstractClass(const std::string& name) : m_Name(name) {}
virtual ~AbstractClass() = default;
std::string GetName() const { return m_Name; }
protected: // protected not private
std::string m_Name;
};
and:
class DerivedClass1 : public AbstractClass {
public:
DerivedClass() : AbstractClass("DerivedClass1") {}
};
Or you can set it in the derived's class constructor:
class AbstractClass {
public:
virtual ~AbstractClass() = default;
std::string GetName() const { return m_Name; }
protected: // protected not private
std::string m_Name;
};
and:
class DerivedClass1 : public AbstractClass {
public:
DerivedClass() : AbstractClass() { m_Name = "DerivedClass1"; }
};
You get the link error because the destructor for AbstractClass needs to be defined even if it is empty.
AbstractClass::~AbstractClass()
{
// Compulsory virtual destructor definition,
// even if it's empty
}
LIVE on Wandbox
Regarding overriding getName: you do not have to. If you do not provide an implementation in the derived class, the one inherited one is used.
Code sugest that problem is how to get a class name? But this is not clearly stated in question (XY problem)
How to handle class name?
You can use RTTI:
class ClassName {
public:
virtual ~ClassName() {} // just to enable RTTI for all decendants
std::string getClassName() {
return typeid(*this).name();
}
};
https://wandbox.org/permlink/LvPdA37arMr0LFQW
But as you can see it adds some extra prefix (it is compiler depended). boost can clean it up:
https://wandbox.org/permlink/8XiB7yVOM0wYVxpl
Related
I have a diamond inheritance structure like:
class Card {
public:
virtual std::string info() const = 0;
}
class Color : public Card {
public:
virtual std::string info() const = 0;
}
class Deploy : virtual public Color {
public:
virtual std::string info() const = 0;
}
class Attack : virtual public Color {
public:
virtual std::string info() const = 0;
}
class Character : public Attack, public Deploy {
public:
std::string info() { return "My Info" };
}
But in the class Character it says to me:
override of virtual function "Card::info" is ambiguous
I want to have just one declaration of info in Character. How can I do it?
Apart from missing some ;s at the end of class definitions and the return statement of Character::info,
The main issue is that are missing the const qualifier from the definition of Character::info.
I would also add override the get help from the compiler if the method does not in fact override a base class method:
//-----------------vvvvv-vvvvvvvv----------------------
std::string info() const override { return "My Info"; };
I have a problem with a static variable within a class.
I'm trying to edit a static variable of a child class without editing the others childs class static variable.
The header file :
class A {
public:
A() {}
void printName() {qDebug() << _name; }
void changeName(QString name) {_name = name;}
private:
static QString _name;
};
QString A::_name = QString("default");
class B : public A {
public:
B() : A() {}
};
class C : public A {
public:
C() : A() {}
};
I'm trying to edit the static _name of my class B without editing the _name of my class C. When I try this code in this main.cpp :
int main(int argc, char *argv[])
{
A *a = new B{};
A *b = new B{};
A *c = new C{};
a->printName();
b->printName();
c->printName();
B *tmp = dynamic_cast<B*>(a);
tmp->changeName("new");
qDebug() << "Then";
a->printName();
b->printName();
c->printName();
}
Here's what I have :
"default"
"default"
"default"
Then
"new"
"new"
"new"
Anyone has any idea on how I could fix this ?
Here's what I've also try :
class A {
public:
A() {}
virtual ~A() {}
void printName() {qDebug() << _name; }
virtual void changeName(QString name) {_name = name;}
private:
static QString _name;
};
QString A::_name = QString("default");
class B : public A {
public:
B() : A() {}
void changeName(QString name) override {_name = name;}
private:
static QString _name;
};
class C : public A {
public:
C() : A() {}
void changeName(QString name) override {_name = name;}
private:
static QString _name;
};
There is only one A::_name, it can only have one value at any given time. Since all your derived types uses the same static member they necessarily all have the same _name value. To fix this, each derived type must provide it's own static member instead.
To avoid repeating the same members in every derived type, you can define them in a templated intermediate class that sits between A and the derived types B and C. Each template specialization has it's own static member. So, provided each derived type supplies a unique value to the intermediate type's template argument, they will have their own names. For example, split A into two classes :
#include <iostream>
#include <string>
class A {
public:
virtual void printName() = 0;
virtual void changeName(std::string name) = 0;
};
template<class T>
class A_impl : public A
{
public:
void printName() override {
std::cout << _name << '\n';
};
void changeName(std::string name) override {
_name = std::move(name);
};
private:
static std::string _name;
};
template<class T>
std::string A_impl<T>::_name = "default";
Then each derived type should inherit from A_impl instead of A. By providing their own type to A_impl, you can be sure each derived type provides a unique template argument :
class B : public A_impl<B> { };
class C : public A_impl<C> { };
Now your test should print
default
default
default
Then
new
new
default
Consider the following:
class Base {
public:
virtual std::string getName() = 0;
...
};
class Derived1 : public Base {
public:
static std::string getClassName() { return("Derived1"); }
std::string getName() { return("Derived1"); }
...
};
class Derived2 : public Base {
public:
static std::string getClassName() { return("Derived2"); }
std::string getName() { return("Derived2"); }
...
};
The idea is that if you have the derived class passed as, say, a template parameter, then you can get its class name via getClassName, while if you have it passed as a pointer to base class, you can get the name via getName.
I have seem a lot of similar questions to this here but all of them seem to ask stuff like "how do I use a static virtual", "why don't static virtuals exist" and various stuff like that, and the answers seem to address that more than what I think the real underlying problem is, which is: how can I avoid having to repeat myself with that code and mentioning the name twice while using as little boilerplate as possible? (Don't Repeat Yourself, or DRY Rule)
I don't want a macro, either.
First off, you can re-use getClassName in getName:
class Derived1 : public Base {
public:
static std::string getClassName() { return("Derived1"); }
std::string getName() override { return getClassName(); }
...
};
Now, all definitions of getName() are identical, so you can put them in a macro to save on typing (and make them more future-proof):
#define GET_NAME() std::string getName() override { return getClassName(); }
class Derived1 : public Base {
public:
static std::string getClassName() { return("Derived1"); }
GET_NAME()
...
};
Or you can bundle getClassName in there as well:
#define GET_NAME(maName) \
static std::string getClassName() { return(maName); } \
std::string getName() override { return getClassName(); }
class Derived1 : public Base {
public:
GET_NAME("Derived1")
...
};
You say "I don't want a macro, either," but macros are a good tool for that, and I wouldn't see a single problem with using them like this. However, if that is not what you want, you can do it without them as well:
template <class Self>
struct GetName : public Base
{
std::string getName() override { return Self::getClassName(); }
};
class Derived1 : public GetName<Derived1> {
public:
static std::string getClassName() { return("Derived1"); }
...
};
class Derived2 : public GetName<Derived2> {
public:
static std::string getClassName() { return("Derived2"); }
...
};
Don't fear data:
class Base {
public:
std::string const Name;
Base(std::string Name) : Name(Name) { }
};
class Derived1 : public Base {
public:
static const std::string Name;
Derived1() : Base { Name } { }
};
const std::string Derived1::Name { "Derived1" }
Make a separate base class that has the single responsibility of providing a class name string:
class FakeRTTI
{
std::string class_name;
public:
FakeRTTI( std::string className ) : class_name(className) {}
getClassName() { return class_name; }
}
With which you can then do this in all classes that need your fake, inefficient, explicit, string-based RTTI:
class Bla : public FakeRTTI
{
public:
Bla() : FakeRTTI("Bla") {}
}
Pro's:
DRY: there is only one ever use of the string "Bla", in its constructor.
Single Responsibility Principle
No virtual function calls
Cons:
Multiple inheritance (is this is con, really?)
You're not using the efficient, standard, C++-based RTTI.
You're still using RTTI (it might well not be feasible to get rid of it, but it is a sign of code smell all the smell).
Another possible solution uses traits and type erasure as in the following example:
#include<string>
#include<iostream>
template<typename> struct NameTraits;
template<typename T>
struct tag {};
class Base {
using func = std::string(*)(void);
template<typename T>
static std::string name() {
return NameTraits<T>::name;
}
public:
template<typename T>
Base(tag<T>): nameF{&name<T>} {}
std::string getName() {
return nameF();
}
private:
func nameF;
};
struct Derived1: Base {
Derived1(): Base{tag<Derived1>{}} {}
};
struct Derived2: Base {
Derived2(): Base{tag<Derived2>{}} {}
};
template<> struct NameTraits<Derived1> { static constexpr char *name = "Derived1"; };
template<> struct NameTraits<Derived2> { static constexpr char *name = "Derived2"; };
int main() {
Base *base = new Derived1;
// Using base class
std::cout << base->getName() << std::endl;
// Using directly the type
std::cout << NameTraits<Derived2>::name << std::endl;
}
Pros:
Name is no longer part of the class and you can easily define a common trait for a family of classes (use simply the same tag for all of them)
You don't have any virtual method
You don't need two methods that do almost the same thing
Cons:
You have to explicitly specify the tag that carries the type to be used during construction
Consider the following abstract class AbstractEngine:
class AbstractEngine {
static void init();
static std::string getName();
};
And consider the following 2 implementor classes:
class Engine1 : public AbstractEngine {
static std::string getName();
};
class Engine2 : public AbstractEngine {
static std::string getName();
};
And, the init() function should call the correct getName() according to the type of class:
void AbstractEngine::init() {
std::cout << getName() << std::endl;
}
For example, If I call Engine1::init(), I would like it to call Engine1::getName() and not AbstractEngine::getName()
How can I make AbstractEngine::init() really to call the correct implementation of getName()?
You can use the CRTP, i.e. make AbstractEngine a template class, then when you inherit, inherit from AbstractEngine<EngineN>:
template <typename T>
class AbstractEngine {
public:
static void init() {
std::cout << T::getName() << std::endl;
}
};
class Engine1 : public AbstractEngine<Engine1> {
public:
static std::string getName() { return "Engine1"; }
};
class Engine2 : public AbstractEngine<Engine2> {
public:
static std::string getName() { return "Engine2"; }
};
Live Demo
If you also need some dynamic polymorphic behaviour, you can make a common non-template base class:
class AbstractEngine {
//I assume you would have some virtual functions here
};
template <typename T>
class AbstractEngineImpl : public AbstractEngine {
public:
static void init() {
std::cout << T::getName() << std::endl;
}
};
class Engine1 : public AbstractEngineImpl<Engine1> {
public:
static std::string getName() { return "Engine1"; }
};
class Engine2 : public AbstractEngineImpl<Engine2> {
public:
static std::string getName() { return "Engine2"; }
};
The getName() method should not be static. Neither the init() method.
You're trying to get polymorphic behaviour, but with static functions. This doesn't make any sense. By definition, polymorphic behaviour is associated with particular instance of objects - but static functions do not have an associated instance.
If you want polymorphic behaviour (as you tag suggests), consider this redesign:
class AbstractEngine {
virtual void init();
virtual std::string getName();
};
class Engine1 : public AbstractEngine {
std::string getName() override;
};
class Engine2 : public AbstractEngine {
std::string getName() override;
};
Is there anyway to have a sort of virtual static member in C++?
For example:
class BaseClass {
public:
BaseClass(const string& name) : _name(name) {}
string GetName() const { return _name; }
virtual void UseClass() = 0;
private:
const string _name;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass("DerivedClass") {}
virtual void UseClass() { /* do something */ }
};
I know this example is trivial, but if I have a vector of complex data that is going to be always the same for all derived class but is needed to be accessed from base class methods?
class BaseClass {
public:
BaseClass() {}
virtual string GetName() const = 0;
virtual void UseClass() = 0;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() {}
virtual string GetName() const { return _name; }
virtual void UseClass() { /* do something */ }
private:
static const string _name;
};
string DerivedClass::_name = "DerivedClass";
This solution does not satify me because I need reimplement the member _name and its accessor GetName() in every class. In my case I have several members that follows _name behavior and tenths of derived classes.
Any idea?
Here is one solution:
struct BaseData
{
const string my_word;
const int my_number;
};
class Base
{
public:
Base(const BaseData* apBaseData)
{
mpBaseData = apBaseData;
}
const string getMyWord()
{
return mpBaseData->my_word;
}
int getMyNumber()
{
return mpBaseData->my_number;
}
private:
const BaseData* mpBaseData;
};
class Derived : public Base
{
public:
Derived() : Base(&sBaseData)
{
}
private:
static BaseData sBaseData;
}
BaseData Derived::BaseData = { "Foo", 42 };
It seems like the answer is in the question - the method you suggested seems to be the right direction to go, except that if you have a big number of those shared members you might want to gather them into a struct or class and past that as the argument to the constructor of the base class.
If you insist on having the "shared" members implemented as static members of the derived class, you might be able to auto-generate the code of the derived classes. XSLT is a great tool for auto-generating simple classes.
In general, the example doesn't show a need for "virtual static" members, because for purposes like these you don't actually need inheritance - instead you should use the base class and have it accept the appropriate values in the constructor - maybe creating a single instance of the arguments for each "sub-type" and passing a pointer to it to avoid duplication of the shared data. Another similar approach is to use templates and pass as the template argument a class that provides all the relevant values (this is commonly referred to as the "Policy" pattern).
To conclude - for the purpose of the original example, there is no need for such "virtual static" members. If you still think they are needed for the code you are writing, please try to elaborate and add more context.
Example of what I described above:
class BaseClass {
public:
BaseClass(const Descriptor& desc) : _desc(desc) {}
string GetName() const { return _desc.name; }
int GetId() const { return _desc.Id; }
X GetX() connst { return _desc.X; }
virtual void UseClass() = 0;
private:
const Descriptor _desc;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass(Descriptor("abc", 1,...)) {}
virtual void UseClass() { /* do something */ }
};
class DerDerClass : public BaseClass {
public:
DerivedClass() : BaseClass("Wowzer", 843,...) {}
virtual void UseClass() { /* do something */ }
};
I'd like to elaborate on this solution, and maybe give a solution to the de-initialization problem:
With a small change, you can implement the design described above without necessarily create a new instance of the "descriptor" for each instance of a derived class.
You can create a singleton object, DescriptorMap, that will hold the single instance of each descriptor, and use it when constructing the derived objects like so:
enum InstanceType {
Yellow,
Big,
BananaHammoc
}
class DescriptorsMap{
public:
static Descriptor* GetDescriptor(InstanceType type) {
if ( _instance.Get() == null) {
_instance.reset(new DescriptorsMap());
}
return _instance.Get()-> _descriptors[type];
}
private:
DescriptorsMap() {
descriptors[Yellow] = new Descriptor("Yellow", 42, ...);
descriptors[Big] = new Descriptor("InJapan", 17, ...)
...
}
~DescriptorsMap() {
/*Delete all the descriptors from the map*/
}
static autoptr<DescriptorsMap> _instance;
map<InstanceType, Descriptor*> _descriptors;
}
Now we can do this:
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.BananaHammoc)) {}
virtual void UseClass() { /* do something */ }
};
class DerDerClass : public BaseClass {
public:
DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.Yellow)) {}
virtual void UseClass() { /* do something */ }
};
At the end of execution, when the C runtime performs uninitializations, it also calls the destructor of static objects, including our autoptr, which in deletes our instance of the DescriptorsMap.
So now we have a single instance of each descriptor that is also being deleted at the end of execution.
Note that if the only purpose of the derived class is to supply the relevant "descriptor" data (i.e. as opposed to implementing virtual functions) then you should make do with making the base class non-abstract, and just creating an instance with the appropriate descriptor each time.
I agree with Hershi's suggestion to use a template as the "base class". From what you're describing, it sounds more like a use for templates rather then subclassing.
You could create a template as follows ( have not tried to compile this ):
template <typename T>
class Object
{
public:
Object( const T& newObject ) : yourObject(newObject) {} ;
T GetObject() const { return yourObject } ;
void SetObject( const T& newObject ) { yourObject = newObject } ;
protected:
const T yourObject ;
} ;
class SomeClassOne
{
public:
SomeClassOne( const std::vector& someData )
{
yourData.SetObject( someData ) ;
}
private:
Object<std::vector<int>> yourData ;
} ;
This will let you use the template class methods to modify the data as needed from within your custom classes that use the data and share the various aspects of the template class.
If you're intent on using inheritance, then you might have to resort to the "joys" of using a void* pointer in your BaseClass and dealing with casting, etc.
However, based on your explanation, it seems like you need templates and not inheritance.
#Hershi: the problem with that approach is that each instance of each derived class has a copy of the data, which may be expensive in some way.
Perhaps you could try something like this (I'm spit-balling without a compiling example, but the idea should be clear).
#include <iostream>
#include <string>
using namespace std;
struct DerivedData
{
DerivedData(const string & word, const int number) :
my_word(word), my_number(number) {}
const string my_word;
const int my_number;
};
class Base {
public:
Base() : m_data(0) {}
string getWord() const { return m_data->my_word; }
int getNumber() const { return m_data->my_number; }
protected:
DerivedData * m_data;
};
class Derived : public Base {
public:
Derived() : Base() {
if(Derived::s_data == 0) {
Derived::s_data = new DerivedData("abc", 1);
}
m_data = s_data;
}
private:
static DerivedData * s_data;
};
DerivedData * Derived::s_data = 0;
int main()
{
Base * p_b = new Derived();
cout getWord() << endl;
}
Regarding the follow-up question on deleting the static object: the only solution that comes to mind is to use a smart pointer, something like the Boost shared pointer.
It sounds as if you're trying to avoid having to duplicate the code at the leaf classes, so why not just derive an intermediate base class from the base class. this intermediate class can hold the static data, and have all your leaf classes derive from the intermediate base class. This presupposes that one static piece of data held over all the derived classes is desired, which seems so from your example.