How to initialize grandparent's (const) property in grandchild in C++? - c++

I know this might look like a trivial question, but I haven't found really an elegant C++ solution to the following problem.
I want to represent a complex (tree-like) hierarchy of a "world" of objects. Let's say Animals. Every animal has some basic const properties.
Like for example a name. Then it also has some methods, but they are not significant for this problem.
class Animal {
public:
const char *GetName() const;
protected:
const char *name;
};
class Insect : public Animal {
...
};
class Butterfly : public Insect {
...
};
In this hierarchy I would like to initialize the name in every derived (grand)child. What is an elegant solution to this?
It is also important to say that in this "world" there be only instances of the tree leaves. That is, there will be no objects "Animal" or "Insect". But there will be objects "Butterfly", "Bee" or "Mosquito".
I know the "standard" way to do this is to put name into constructor:
Animal::Animal(const char *name) : name(name) {}
Insect::Insect(const char *name) : Animal(name) {}
Butterfly::Butterfly() : Insect("Butterfly") {}
But if there are more of these properties, the derived classes need also some initialization and the hierarchy has more levels it can become quite a mess:
Animal::Animal(const char *name) : name(name) {}
Vertebrate::Vertebrate(const char *name) : Animal(name) {}
Mammals::Mammals(const char *name) : Vertebrate(name) {}
Ungulate::Ungulate(const char *name) : Mammals(name) {}
Horse::Horse() : Ungulate("Horse") {}
Another option I can see is to drop the const and assign directly in the grandchild's constructor:
class Animal {
public:
const char *GetName() const;
protected:
std::string name;
};
Horse::Horse() {this->name = "Horse";}
But that is also not optimal, because the const is lost and it is more prone to errors (the initialization can be forgotten).
Is there some better way to do this?

Hm - hope that I get not locked out from SO for that answer, but you could use a virtual base class that implements the name-property. Thereby, you will not have to propagate initialization in a base class all way through the hierarchy but could directly address the "very base" constructor with the name-property. Furthermore, you will actually be enforced to call it in any "Grandchild"-class, so you can't forget it by accident:
class NamedItem {
public:
NamedItem(const char* _name) : name(_name) {}
const char *GetName() const;
protected:
const char *name;
};
class Animal : public virtual NamedItem {
public:
Animal(int mySpecificOne) : NamedItem("") {}
};
class Insect : public Animal {
public:
Insect(int mySpecificOne) : Animal(mySpecificOne), NamedItem("") {}
};
class Butterfly : public Insect {
};

The elegant solution is to pass arguments through initialisation. For example, if the "name" variable was the name of the Butterfly (such as "sally" or "david") then it would be obvious it has to be done through initialisation. If you are finding that is ugly, as it is here, it may indicate that your data decomposition/class heirarchy are at fault. In your example every Butterfly object would have an identical set of properties that really refer to their class rather than each instance, ie they are class variables not instance variables. This implies that the "Butterfly" class should have a static pointer to a common "Insect_Impl" object (which might have a pointer to a single "Animal_Impl" object etc) or a set of overridden virtual functions. (Below I only show one level of heirarchy but you should be able to work out more levels)
// Make virtual inherited functionality pure virtual
class Animal {
private:
std::string objName; // Per object instance data
public:
virtual ~Animal(std::string n): objName(n) {}
virtual std::string const& getName() = 0; // Per sub-class data access
virtual std::string const& getOrder() = 0; // Per sub-class data access
std::string const& getObjName() { return this->objName; }
};
// Put common data into a non-inherited class
class Animal_Impl{
private:
std::string name;
public:
Animal_Impl(std::string n): name(n);
std::string const& getName() const { return this->name; }
};
// Inherit for per-instance functionality, containment for per-class data.
class Butterfly: public Animal{
private:
static std::unique< Animal_Impl > insect; // sub-class data
public:
Butterfly(std::string n): Animal(n) {}
virtual ~Butterfly() {}
virtual std::string const& getName() override {
return this->insect->getName(); }
virtual std::string const& getOrder() override {
static std::string order( "Lepidoptera" );
return order; }
};
// Class specific data is now initialised once in an implementation file.
std::unique< Animal_Impl > Butterfly::insect( new Animal_Impl("Butterfly") );
Now using the Butterfly class only needs per-instance data.
Butterfly b( "sally" );
std::cout << b.getName() << " (Order " << b.getOrder()
<< ") is called " << b.getObjName() << "\n";

The issue with your alternative, or any alternative leaving name non-const and protected, is that there is no guarantee that this property is going to be setup properly by the subclasses.
What does the following class give you ?
class Animal {
public:
Animal(const char* something)
const char *GetName() const;
private:
const char *name;
};
The guarantee of the immutability of the Animal interface, which can be a big plus when doing multithreading. If an object is immutable, multiple threads can use it without being a critical resource.
I know the "standard" way to do this is to put name into constructor:
... But if there are more of these properties, the derived classes
need also some initialisation and the hierarchy has more levels it can
become quite a mess
It is not messy at all. Given that there is only one place where the members of object A are being initialised, and it is within the constructor of their subclasses.

Related

Where to put member variables in my interface? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 months ago.
Improve this question
The c++ guidelines say not to put any data in the base class and also not to use trivial getter and setter methods, but rather just member variables, but where do I put the member variables in my data base access implementation? If I put it in one of the derived classes, I get the compiler error that my class db_interface does not have such a member.
#include <boost/core/noncopyable.hpp>
#include <postgresql/libpq-fe.h>
#include <sqlite3.h>
#include <iostream>
#include <string>
class db_interface : boost::noncopyable{
public:
void connect() const {connect_to_DB();}
virtual ~db_interface(){};
private:
virtual void connect_to_DB() const = 0;
};
class postgreSQL : public db_interface{
private:
void connect_to_DB() const { std::cout << "THIS IS POSTGRESQL"<< std::endl; }
};
class liteSQL : public db_interface{
public:
std::string dbName;
private:
void connect_to_DB() const { std::cout << "THIS IS LIGHTSQL"<< std::endl; }
};
class DBFactory {
public:
virtual db_interface *createDB(std::string) = 0;
};
class Factory: public DBFactory {
public:
db_interface *createDB(std::string type) {
if(type == "LiteSQL") {
return new liteSQL;
}
else if(type == "PostgreSQL") {
return new postgreSQL;
}
return nullptr;
}
};
It's worth pointing out the guidelines are just that. Some of them even contradict each other. It's up to you to be the engineer and decide what guidelines make sense for you and your project.
However, these guidelines do not really contradict each other.
The first one you linked to is: C.133: Avoid protected data
The other guideline linked in that one is: C.121: If a base class is used as an interface, make it a pure abstract class
The other guideline linked is the one you seem to be skipping and subsequently tripping yourself over: C.9: Minimize exposure of members
C.133 links to last one with the text Prefer private data.
The ideas being presented do not conflict, but they do take the separation of concerns to a level that is less common in C++ land.
Mainly, your interface should just be an interface. In that regard, putting data in your interface makes no sense.
You can then derive from that interface to create your 'base' class. When here, don't make your data protected. Make it private. Your base class is then the only class responsible for that data. Protected functions like getters and setters do make sense here for your derived classes to make changes which your base class alone is responsible for handling/validating.
On top of that, I actually don't like the idea of the interface being all public pure virtual functions and instead I prefer NVI or Non-Virtual Interfaces. Here's a short example:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// Interface
class PetInterface {
public:
virtual ~PetInterface() = default;
std::string speak() const { return speak_v(); }
std::string name() const { return name_v(); }
private:
virtual std::string speak_v() const = 0;
virtual std::string name_v() const = 0;
};
// Base class
class Pet : public PetInterface {
public:
Pet() = default;
Pet(std::string name, std::string vocal) : m_name(name), m_vocal(vocal) {}
virtual ~Pet() = default;
private:
std::string m_name;
std::string m_vocal;
protected:
std::string name() const { return m_name; }
std::string vocal() const { return m_vocal; }
};
class Dog final : public Pet {
public:
Dog() = default;
Dog(std::string name) : Pet(name, "Woof") {}
private:
std::string speak_v() const override { return vocal(); }
std::string name_v() const override { return name(); }
};
class Cat final : public Pet {
public:
Cat() = default;
Cat(std::string name) : Pet(name, "Meow") {}
private:
std::string speak_v() const override { return vocal(); }
std::string name_v() const override { return name(); }
};
int main() {
std::vector<std::unique_ptr<PetInterface>> pets;
pets.emplace_back(new Dog("Fido"));
pets.emplace_back(new Cat("Dame Whiskers"));
for (const auto& i : pets) {
std::cout << i->name() << " says \"" << i->speak() << "\"\n";
}
}
Output:
❯ ./a.out
Fido says "Woof"
Dame Whiskers says "Meow"
Pet is still an abstract class, as only 'leaf' classes should be concrete.
One final note is that you don't need boost to make a thing non-copyable. Just = delete the copy constructor and copy assignment operator.
You should use use trivial getter and setter methods. Pure virtual in the base class, and implemented in derived classes.
From C++ Core Guidelines:
We do not suffer the delusion that every one of these rules can be effectively applied to every code base... Consider these rules ideals for new code, opportunities to exploit when working on older code, and try to approximate these ideals as closely as feasible.
You should not follow Avoid trivial getters and setters because you are implementing a Database interface, and the express purpose of a database is "setting" and "getting".

Access static const variable from derived classes

I want to set name property in each derived class. And also want to acess this value like Bar1::s_name . My below code doesn't work. So how should I archive my desire?
class Parent {
public:
static std::string getName() {
return s_name;
}
const static std::string s_name;
};
class Bar1 : public Parent {
public:
Bar1() : s_name("Bar1") {}
};
class Bar2 : public Parent {
public:
Bar2() : s_name("Bar2") {}
};
int main() {
Bar1 b;
b.getName();
return 0;
}
Presumably you are wanting to use this in some polymorphic context. If so, you can't use static methods, because they don't exhibit polymorphic behaviour. Additionally, static members will be the same for every instance, including derived objects.
You probably want something like this:
class Parent {
public:
virtual std::string getName() {
return "Parent";
}
};
class Bar1 : public Parent {
public:
virtual std::string getName() override {
return "Bar1";
}
};
class Bar2 : public Parent {
public:
virtual std::string getName() override {
return "Bar2";
}
};
If you also want to be able to access the name statically like Bar1::s_name, you need a static member for each class:
class Parent {
public:
virtual std::string getName() {
return s_name;
}
const static std::string s_name;
};
const std::string Parent::s_name = "Parent";
//likewise for the others
I thing you do not understand properly what static (in this context) means.
Variable defined as static in class means, that there is only one instance of it. So s_name in both Bar1 and Bar2 adresses to one variable.
Method defined as static in class means, that it is not bound to specific instance of that class, but rather to all (maybe none) instances of that class. So it is better to call static method using B::getName() instead of b.getName() (it is less confusing).
Also, because you defined s_name as const static you made that a constant, which compiler does even treat like a variable in runtime, but rather like a constant.
you should define all static variable. definition is missing in your code.
add below line to your program, it will work.
string Parent::s_name = "\0";

C++ Creating Child Class from a Parent Class that's already been initialised

I have a class "Player". Its members are simple strings and ints and I've got Getters and Setters for each of these...basic stuff: (there's a load of members so I've just given 3 to shrink the code):
PLAYER.H
class Player
{
private:
string Name;
string Role;
int FFDefence;
......etc
public:
//constructor function
Player(
string Name = "Not Stated",
string vRole = "Not Stated",
int vFFDefence = 0,
......etc
)
//Getter Functions
string GetName() const;
string GetRole() const;
int GetFFDefence() const;
.....etc
//Setter Functions
void SetName (string x);
void SetRole(string x);
void SetFFDefence(int x);
......etc
};
PLAYER.CPP
Player::Player( string vName,
string vRole,
int vFFDefence,
......etc
{
Name = vName;
Role = vRole;
FFDefence = vFFDefence,
......etc
}
//getter functions
string Player::GetName() const {return Name; };
string Player::GetRole() const {return Role; };
int Player::GetFFDefence() const {return FFDefence; };
.....etc
//Setter Functions
void Player::SetName(string x) { Name = x ; };
void Player::SetRole(string x) { Role = x ; };
void Player::SetFFDefence(int x) { FFDefence = x ; };
......etc
So yeah - pretty bog standard......now I have a second class where one of the member functions is a Player Class itself.
BATTER.H
class Batter
{
private:
Player ID;
int Touch;
....etc
public:
Batter(Player vID, int vTouch = 0....etc);
//Getter Functions
string GetRole() const;
int GetFFDefence() const;
int GetBFDefence() const;....and so on.
OK - that's the code out of the way!!!!
So I've got it doing everything I want in terms of passing variables in and out....so I can create
Player Dave ("Dave", "Opener", 98, ....etc)
then later on (when I need it) create
Batter OnStrike (Dave, 10, .....etc)
All gravy....OK so I've started looking into inheritance and realized this is what I should be doing....back converting not a problem (did this with arrays and vectors the other day)...
Here's my problem:
With what I've got now, I can create "Player Dave" and then pass him into the subclass of Batter whenever I need to. How do I do the same with traditional inheritance? How do I take a specific instance (already created) of Player and use that as the parent for a specific instance of the child class Batter? As far as I can deduce at the moment, you need to create both at the same time.
Just initialize your base object with the object provided:
class Player
{
Player(Player const&); // copy constructor (might be implicitly generated)
...
};
class Batter:
public Player
{
Batter(Player const& p, other arguments):
Player(p),
...
{
...
}
};
On the other hand, there's the question whether inheritance of Batter from Player is the right tool in your case. The fact that you pass a Player object to construction hints at the fact that a Player may become a batter, and maybe later also stop being a batter. That is, Batter is actually a role which the player may temporarily have. Therefore it may be a better idea to separate the Player object from the role, by having a separate Role hierarchy where Batter and Pitcher derive from Role, and Player has a method which returns the current role, and another which can assign another role to the player.
The idea with polymorphism is that if you have some class:
class Batter : public Player
Then every batter is also a player. So, for example, if you had a batter called dave, you'd be able to use dave wherever a Player was expected. You could for example:
int FunctionThatDoesSomething(Player &p, string some_parameter, ...);
...
FunctionThatDoesSomething(dave, "foo", ...);
Be careful to avoid slicing, which is when you accidentally make a base class copy of a subclass (this does not preserve subclass specific state. If you need to pass dave around, make sure you only refer to dave, don't copy dave. dave doesn't like to be copied.)
How exactly you build your players and batters is up to you. For example, your might have constructors with these signatures:
Player::Player(string name, string role, int vFFDefense);
Batter::Batter(Player &p, int vTouch, int moreStats);
Under some circumstances this might be convenient, but it's not particularly efficient because you have to create and copy the base class (not that efficiency is a big deal for small classes like this, but there's no point in trying to do things the dumb way). You would be better off making a constructor that takes everything it needs, and uses subobject initialization:
Batter::Batter(string name, string role, int vFFDefense, int moreBaseStats, int vTouch, int moreStats) : Player(name, role, vFFDefense, moreBaseStats)
{
...
But your implementation is ultimately up to you.
You are doing aggregation here, not inheritance. A Batter has a player. Inheritance would be a batter is a player.
Your design is good, you don't want to do inheritance for this.
While it's okay to say a Batter is always a Player from a conceptual point of view in this case, when you are dealing with a Batter, much of what player describes is irrelevant and when dealing with them as a player, they may not be batting.
Baseball is a bit foreign to me, but if you went down the inheritance route, you'd have descendants of player for each role in the team and get in a right mess when your pitcher came out to bat.
A classic illustration of the inheritance route.
Is
Animal -> Fliers -> Bird -> Merlin
-> Runners -> Rodent -> Gerbil
Where do you put Bat and Ostrich?
You are left with saying a Bat is a bird, inventing a new class FlyingRodent, or Rodent having two parents...
All of which will lead to a confusing bug fest.
View all unconscious reaches for the inheritance hammer with extreme suspicion.
It really depends how you actually want your code factored.
Will a given Player ever become anything other than a Batter? If they can, then it is probably best to use aggregation (in a similar way to how you do now).
If you are aggregating then maybe use another class to hold the data. You could have a PlayerInfo class or struct and aggregate that:
struct PlayerInfo
{
string role_;
int ff_defence_;
...
};
class Player
{
public:
Player(PlayerInfo const& info)
: info_(info)
{}
virtual ~Player() = 0;
virtual void doSomething();
PlayerInfo const& getPlayerInfo() const { return info_; }
private:
PlayerInfo info_;
};
class Batter : public Player
{
public:
Batter(PlayerInfo const& info)
: Player(info)
{}
virtual void doSomething();
};
If you actually want the inheritance then other answers here tell you what you need to do - construct an instance of Batter and pass on the constructor arguments to a constructor of the class you derive from (e.g. Batter) to initialize it.
Think carefully about what are you trying to express in your code.
The reason you would want to have Batter derived from Player is if you need virtual functions in Player that are implemented in Batter and do something different depending upon whether or not it is a Player or a Batter.
As an aside, its best to keep base classes abstract if possible, so Player would never be instantiated directly and would always need to be derived. I'd recommend reading Scott Meyers 'More Effective C++' to understand why this is. There's a section in there devoted to that. In fact some of the finer points of inheritance and OO design in general are nicely explained.
What you may actually want is something slightly different depending upon where you anticipate your model to change, and additionally where you you need it to have the dynamic behaviour possible through the use of virtual functions?
You could have a Player class that has all your player specific details. Then you could have a PlayerBehaviour class that implements what the player does:
class Player;
class PlayerBehaviour
{
public:
virtual ~PlayerBehaviour() = 0;
virtual void doSomething(Player* player) = 0;
};
inline PlayerBehaviour::~PlayerBehaviour() {}
class BatterBehaviour : public PlayerBehaviour
{
public:
virtual void doSomething(Player* player) {
if (player->isAngry()) {
throwBatOnFloor();
}
}
void throwBatOnFloor();
};
class Player {
public:
Player(...stuff...);
void doSomething() {
if (behaviour_.get()) {
behaviour_->doSomething(this);
}
}
private:
auto_ptr<PlayerBehaviour> behaviour_;
// Due to the auto_ptr, the default copy and assignment operators are
// dangerous. You could use a smart pointer or implement
// these by having a clone() function in the behaviour class.
// Therefore copy/assign are private to prevent accidental misuse.
Player(Player const&);
Player& operator=(Player const&);
};
So, inheriting Batter from Player models the situation as a Batter is-a Player.
Having a Behaviour models the situation as a Player has-a Behaviour such as a Batter.
Stop using the "parent" and "child" terminology, think of "base" classes and "derived" classes ... that's what everyone else calls them. "Parent" and "child" can be used in too many other ways (e.g. an object that owns another one) so it's confusing terminology if you're talking about an inheritance relationship.
The derived class contains an entire instance of the base type inside itself. When the derived constructor starts executing the first thing it does is construct all its bases, which it does by calling their constructors. So the derived class can control how the base is constructed by passing it the right arguments:
class Base {
public:
Base(std::string nm) : name(nm) { }
protected:
std::string name;
};
class Derived : public Base {
public:
// construct my base by passing name to it
Derived(std::string name, int ii) : Base(name), i(ii) { }
private:
int i;
};
Derived d("Dave Derived", 1);
This creates both the Base and Derived objects at the same time (one inside the other) which is probably what you want.
If do have an existing Base object and you want the base part of the derived object to be the same as that other one then you can pass it an object to copy:
class Base {
public:
Base(std::string nm) : name(nm) { }
protected:
std::string name;
};
class Derived : public Base {
public:
// construct my base by passing name to it
Derived(std::string name, int ii) : Base(name), i(ii) { }
// construct my base by passing another Base to it:
Derived(const Base& b, int ii) : Base(b), i(ii) { }
private:
int i;
};
Base b("Barry Base");
Derived d(b, 2);
This doesn't put the existing Base object, b, inside the Derived one, instead it makes the base object a copy of the object b, by calling the Base copy constructor, so now there are two Base objects, the original b and the one inside d. This is closer to your original code, where the Batter contains a Player member, but now it's a base class not a member.
If you do want to use inheritance, the first form is probably more appropriate, where you pass arguments to the derived class and it uses those arguments to create the base.

Memory sharing; Inheritance; Base and Derived instances; C++

Ok, this example is pretty straight-forward for the concept I'm trying to understand. I'll just show you the code:
class Base
{
protected:
string name;
public:
virtual string getName() const { return this->name; }
virtual void setName(string name) { this->name = name; }
....
}
class Derived : public Base
{
private:
double price;
....
}
main(int argc, char** argv)
{
Base* base = new Base("Base Class");
Derived* derived = new Derived(base, 453.21);
derived->setName("Name changed!");
cout << "Name of instance: " << base->getName() << endl;
// Desired effect
Output: 'Name changed!'
// Actual effect
Output: 'Base Class'
....
}
The issue for me is this. I want to create an instance of derived class with reference to already created instance of base class, so when I change any member variable of base class trough the derived instance, I can see the change on previously created base instance in the way demonstrated above.
Note: I hope that you will manage to comprehend what I meant, as I am aware that my terminology is probably little off. Please, don't be harsh. :)
Note: I won't be showing / writing constructors, since I am not sure what is the best way to do this, if even any exists and the syntax may be incorrect.
This seems to indicate the problem:
Base* base = new Base("Base Class");
Derived* derived = new Derived(base, 453.21);
as it is usually not necessary to construct the Base class separatly. Your derived class will already contain a Base instance implicitly, you don't have to add a pointer to one manually and set it from the ctor. I don't know how your ctor looks, but it should look like this:
Derived(const std::string& name, double p) : Base(name), price( p ) {}
If this enough to fix it yourself, good, otherwise post all the code of your example. Instead of the two lines from your code that I quoted above, it should look more like:
Derived* derived = new Derived("Base Class", 453.21);
If you post the code of Derived, it should be obvious for us and it will be much easier to explain it to you on your concrete example.
The way you are trying to do is weird, but you can simply use inheritance concept like this code:
class Base
{
public:
Base(const string &name) : name(name) {}
virtual void setName(const string &name) { this->name = name; }
virtual string getName() const { return name; }
protected:
string name;
};
class Derived : public Base
{
public:
Derived(const string &name, double price) : Base(name), price(price) {}
private:
double price;
};
int main()
{
Derived* derived = new Derived("Base Class", 453.21);
derived->setName("Name changed!");
Base *base = derived;
cout << "Name of instance: " << base->getName() << endl;
}
Output
Name of instance: Name changed!
You don't need a create Base object and pass it to the derived object.
Instead, create a derived object and pass its address to a Base pointer.

How to make a member function in an inheritance hierarchy return always the same value?

I have an inheritance hierarchy and I want to make each class in this hierarchy have a set of attributes which are particular for that class and which do not change during the run of the program. For example:
class Base
{
public:
const std::string getName() const;
bool getAttribute1() const;
int getAttribute2() const;
};
Now I want these functions to return the same result all the time. Furthermore, when another class inherits Base this class should have its own set of attributes and any instance of this derived class should have the same attributes. Also the name should be unique for each class.
I want to know a way to make this as transparent and elegant as possible. Sofar I have considered 2 ideas that I can use:
Make some lock system.
That is provide setters for these attributes, but make them throw a runtime exception when they are called more than once.
Make the getters pure virtual.
In this case, the result of the functions would not be stored inside the object itself. This would make it vaguely clear that the result depends on the dynamic type.
Both ideas sound incredibly lousy, so I need your help.
I am new to C++, but I know there are a lot of idioms and patterns to solve general problems like this one. Do you know any?
I have an inheritance hierarchy and I want to make each class in this hierarchy have a set of attributes which are particular for that class and which do not change during the run of the program
Well, then just provide the corresponding values as arguments to a class constructor, and do not expose any setter method on the public interface. This will make sure the values remain constant throughout the life-time of the object.
To protect against possible errors that would alter the value of those data members from member functions of your class (which of course can access the private data), make those data members const. Notice, that this will force you to initialize those members in the constructor's initializer list.
class Base
{
public:
// Forwarding constructor (requires C++11)
Base() : Base("base", true, 42) { }
const std::string getName() const { return _s; }
bool getAttribute1() const { return _a1; }
int getAttribute2() const { return _a2; }
protected:
// Constructor that can be called by derived classes
Base(std::string s, bool a1, int a2)
: _s(s), _a1(a1), _a2(a2) { }
private:
const std::string _s;
const bool _a1;
const bool _a2;
};
Derived classes would then just construct the base subobject with the appropriate arguments:
class Derived : public Base
{
public:
// Provide the values for the constant data members to the base constructor
Derived() : Base("derived", false, 1729) { }
};
This way you would not incur in the overhead of a virtual function call, and you won't have to rewrite similar virtual functions for each of these members in derived classes.
Make them virtual and hard-code the result which the functions should return:
class Base
{
public:
virtual const std::string getName() const { return "BaseName"; }
virtual bool getAttribute1() const { return whatEverAttributeValueYouWant; }
virtual int getAttribute2() const { return attributeValueHere; }
};
class Derived : public Base {
public:
virtual const std::string getName() const { return "DerivedName"; }
virtual bool getAttribute1() const { return whatEverOtherAttributeValueYouWant; }
virtual int getAttribute2() const { return otherAttributeValueHere; }
};
If you want to describe classes rather than objects, use (kind-of) traits:
template<class T> struct AttributeValues;
template<> struct AttributeValues<Base> {
static const std::string name () { return "BaseName"; }
};
template<> struct AttributeValues<Derived> {
static const std::string name () { return "DerivedName"; }
};
//...
auto nameBase = AttributeValues<Base>::name ();
auto nameDerived = AttributeValues<Derived>::name ();