What I'm trying to do is to change a variable from class A inside class B and make it the same in class C
class A
{
protected:
string name = "A";
};
class B: public A
{
protected:
string A::name="B";
};
class C: public B
{
// here i want "name" to be "B"
};
But the problem is, i'm getting an error in class C "illegal qualified name in member declaration".
You can't do it like this. If the field is being initialized in the base class, it is being initialized only in the base class. In other classes you can only change already initialized field.
One of the ways to do what you want can be passing the value in the constructor. So:
class A
{
public:
A(std::string initName = "A") : name(std::move(initName)) {}
protected:
string name;
};
class B: public A
{
public:
B() : A("B") {}
};
class C: public B
{
// name will be "B" here
};
what you want is to initialize the value of your variable in the constructor
public class B: public A
{
public:
B():name{"B"}{};
}
If the names of the classes are static and you don't mind using polymorphism, you could add a virtual member function returning the name of the class. Simply override the function in the derived classes to return a different name.
Example:
#include <iostream>
#include <memory>
#include <vector>
class A {
public:
virtual ~A() = default;
virtual const std::string& name() const {
static const std::string rv = "A";
return rv;
}
};
class B : public A {
public:
const std::string& name() const override {
static const std::string rv = "B";
return rv;
}
};
class C: public B {
// doesn't override name() - will be named "B"
};
int main() {
std::vector<std::unique_ptr<A>> objs; // Storage of base class pointers.
objs.emplace_back(std::make_unique<A>()); // Add pointers to...
objs.emplace_back(std::make_unique<B>()); // objects of different...
objs.emplace_back(std::make_unique<C>()); // derived classes.
// call the virtual member function through the base class pointer
for(auto& uptr : objs) {
std::cout << uptr->name() << '\n';
}
}
Output
A
B
B
Related
I have a base class B with derived classes X, Y and Z (in fact, more than 20 derived classes). Each class has a tag() function that identifies which (derived) class it is. My program stores instances of the derived classes as pointers in a vector defined as vector<B*>. Each derived class may appear in this vector 0..n times.
I would like to have a function that looks through the vector for instances of a derived type and returns a new vector with the type of the derived class, eg
#include <vector>
using namespace std;
class B {
public:
// ...
virtual int tag() {return 0xFF;};
};
class X : public B {
// ...
int tag() {return 1;};
vector<X*> find_derived(vector<B*> base_vec) {
vector<X*> derived_vec;
for (auto p : base_vec) {
if (p->tag() == tag()) {
derived_vec.push_back((X*) p);
}
}
return derived_vec;
}
};
Obviously I don't want to have to define find_derived in each derived class but I don't see how to do this as a virtual function. Currently I am doing it using a macro but, since I am learning C++, I woudl prefer a method that used language constructs rather than those in the pre-processor. Is there another way?
One possibility:
template <typename D>
class FindDerivedMixin {
public:
vector<D*> find_derived(const vector<B*>& base_vec) {
int my_tag = static_cast<D*>(this)->tag();
vector<D*> derived_vec;
for (auto p : base_vec) {
if (p->tag() == my_tag) derived_vec.push_back(static_cast<D*>(p));
}
return derived_vec;
}
};
class X : public B, public FindDerivedMixin<X> {};
Like the previous answer, what you need is some template programming.
This is an example without mixin though:
#include <vector>
#include <iostream>
#include <type_traits>
#include <string>
//-----------------------------------------------------------------------------
// Base class
class Base
{
public:
virtual ~Base() = default;
// pure virtual method to be implemented by derived classes
virtual void Hello() const = 0;
protected:
// example of a constuctor with parameters
// it is protected since no instances of Base
// should be made by accident.
explicit Base(const std::string& message) :
m_message(message)
{
}
// getter for private member variable
const std::string& message() const
{
return m_message;
}
private:
std::string m_message;
};
//-----------------------------------------------------------------------------
// Class which contains a collection of derived classes of base
class Collection
{
public:
Collection() = default;
virtual ~Collection() = default;
// Add derived classes to the collection.
// Forward any arguments to the constructor of the derived class
template<typename type_t, typename... args_t>
void Add(args_t&&... args)
{
// compile time check if user adds a class that's derived from base.
static_assert(std::is_base_of_v<Base, type_t>,"You must add a class derived from Base");
// for polymorphism to work (casting) we need pointers to derived classes.
// use unique pointers to ensure it is the collection that will be the owner of the
// instances
m_collection.push_back(std::make_unique<type_t>(std::forward<args_t>(args)...));
}
// Getter function to get derived objects of type_t
template<typename type_t>
std::vector<type_t*> get_objects()
{
static_assert(std::is_base_of_v<Base, type_t>, "You must add a class derived from Base");
// return non-owning pointers to the derived classes
std::vector<type_t*> retval;
// loop over all objects in the collection of type std::unique_ptr<Base>
for (auto& ptr : m_collection)
{
// try to cast to a pointer to derived class of type_t
type_t* derived_ptr = dynamic_cast<type_t*>(ptr.get());
// if cast was succesful we have a pointer to the derived type
if (derived_ptr != nullptr)
{
// add the non-owning pointer to the vector that's going to be returned
retval.push_back(derived_ptr);
}
}
return retval;
}
private:
std::vector<std::unique_ptr<Base>> m_collection;
};
//-----------------------------------------------------------------------------
// some derived classes for testing.
class Derived1 :
public Base
{
public:
explicit Derived1(const std::string& message) :
Base(message)
{
}
virtual ~Derived1() = default;
void Hello() const override
{
std::cout << "Derived1 : " << message() << "\n";
}
};
//-----------------------------------------------------------------------------
class Derived2 :
public Base
{
public:
explicit Derived2(const std::string& message) :
Base(message)
{
}
virtual ~Derived2() = default;
void Hello() const override
{
std::cout << "Derived2 : " << message() << "\n";
}
};
//-----------------------------------------------------------------------------
int main()
{
Collection collection;
collection.Add<Derived1>("Instance 1");
collection.Add<Derived1>("Instance 2");
collection.Add<Derived2>("Instance 1");
collection.Add<Derived2>("Instance 2");
collection.Add<Derived1>("Instance 3");
// This is where template programming really helps
// the lines above where just to get the collection filled
auto objects = collection.get_objects<Derived1>();
for (auto& derived : objects)
{
derived->Hello();
}
return 0;
}
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
I haven't worked with derived classes and polymorphism in a while, and I can't figure out how to access a derived class data item.
// Quick example
class Base {
string data1; // data1 = "FOO"
};
class ChildA : public Base {
string data2;
};
int main() {
Base **list;
list = new Base*[1];
base[0] = new ChildA(// data2 = "BAR");
std::cout << base[0]->data1; // FOO
std::cout << base[0]->data2; // Error; no member named "data2" in Base
Is it possible to retrieve the derived data from the base class array?
When you're looking at an instance of a derived class through a pointer to the base class, you can only see the members of the base class, because generally, you wouldn't know what subtype instance you are looking at. The point of polymorphism and virtual functions is that in many cases, you can work with subtype instances without knowing their actual type. For instance, if you want to print information about an instance, and you want data2 to be included when you print a ChildA, you would create a virtual toString() function in Base and override it in ChildA to include data2. Then, you can call toString() without knowing the actual type, and if your instance is actually a ChildA, you'll get data2.
class member variable by default is private.
by using base class pointer, you can not get derived class member var at all.
If you would like to do so, you may want to implement virtual getter function, it will help you getting private member function from derived class.
If the base class interface must have knowledge of data potentially held in a derived class, here is one of the few ways that is not horribly dangerous.
#include <iostream>
#include <vector>
#include <utility>
#include <memory>
#include <stdexcept>
using namespace std;
class Base {
public:
Base(std::string d1 = {"FOO"} ) : _data1 { std::move(d1) } {}
virtual ~Base() = default; // because polymorphism without a virtual base class is naughty
const string& data1() const { return _data1; }
virtual bool has_data2() const { return false; }
virtual const string& data2() const {
throw invalid_argument {"I don't have data2"};
};
private:
string _data1; // data1 = "FOO"
};
class ChildA : public Base {
public:
ChildA(std::string d2, std::string d1 = {"FOO"})
: Base { std::move(d1) }
, _data2 { std::move(d2) }
{}
bool has_data2() const override { return true; }
const std::string& data2() const override {
return _data2;
};
private:
string _data2;
};
int main()
{
vector<unique_ptr<Base>> bases;
bases.push_back(unique_ptr<Base>(new ChildA("bob")));
bases.push_back(unique_ptr<Base>(new Base("not foo")));
for(const auto& p : bases) {
cout << p->data1() << ", " << (p->has_data2() ? p->data2() : "no data 2") << endl;
}
return 0;
}
Basically I have a class let's say Parameter that has a get and set variable.
I also have a base class let's say Vehicle that has a method registerParameter(...) that takes a pointer to function member as getter and a pointer to function member as setter. This method is then supposed to write those two pointers into an object of the parameter class and throws this object into a vector.
And last but not least we have a derived class let's say Car and we call registerParameter(...) with the string "color" as parameter name and a getter and setter from this derived class.
Example in code:
Parameter file
#ifndef BASE_H
#define BASE_H
#include "base.h"
class Parameter
{
std::string (Base::*get)();
void (Base::*set)(std::string);
};
#endif
Base file
#ifndef PARAMETER_H
#define PARAMETER_H
#include <vector>
#include "parameter.h"
class Base
{
public:
std::vector<Parameter> list;
void registerNew(std::string (Base::*get)(), void (Base::*set)(std::string))
{
Parameters parameter;
parameter.get = get;
parameter.set = set;
list.push_back(parameter);
}
};
#endif
Derived file
class Derived
{
public:
Derived derived()
{
registerNew(&getColor, &setColor);
}
std::string getColor()
{
return this->color;
}
std::string setColor(std::string newColor)
{
this->color = newColor;
}
private:
std::string color;
};
I've been thinking about this for days now and I really need the solution until friday evening.
You cannot do what are trying:
The types std::string (Base::*)() and std::string (Derived::*)() are very different. std::string (Derived::*)() cannot be auto converted to std::string (Base::*)().
Take the following scenario.
struct Base
{
int foo() { return 10; }
};
struct Derived : Base
{
int bar() { return 20; }
};
int main()
{
Base base;
int (Base::*bf)() = &Base::foo;
(base.*bf)(); // Should be able to call Base:foo(). No problem.
bf = &Derived::bar; // This is a compiler error. However, if this were allowed....
(base.*bf)(); // Call Derived::bar()?? That will be a problem. base is not an
// instance of Derived.
}
Update
You can do something like:
#include <string>
#include <vector>
class Base;
// Create a base class Functor that provides the interface to be used by
// Base.
struct Functor
{
virtual ~Functor() {}
virtual std::string get(Base& base) = 0;
virtual void set(Base& base, std::string) = 0;
};
// Create a class template that implements the Functor interface.
template <typename Derived> struct FunctorTemplate : public Functor
{
// typedefs for get and set functions to be used by this class.
typedef std::string (Derived::*GetFunction)();
typedef void (Derived::*SetFunction)(std::string);
// The constructor that uses the get and set functions of the derived
// class to do itw work.
FunctorTemplate(GetFunction get, SetFunction set) : get_(get), set_(set) {}
virtual ~FunctorTemplate() {}
// Implement the get() function.
virtual std::string get(Base& base)
{
return (reinterpret_cast<Derived&>(base).*get_)();
}
// Implement the set() function.
virtual void set(Base& base, std::string s)
{
(reinterpret_cast<Derived&>(base).*set_)(s);
}
GetFunction get_;
SetFunction set_;
};
class Base
{
public:
std::vector<Functor*> functorList;
void registerFunctor(Functor* functor)
{
functorList.push_back(functor);
}
};
class Derived : public Base
{
public:
Derived()
{
// Register a FunctorTemplate.
registerFunctor(new FunctorTemplate<Derived>(&Derived::getColor,
&Derived::setColor));
}
std::string getColor()
{
return this->color;
}
void setColor(std::string newColor)
{
this->color = newColor;
}
private:
std::string color;
};
Your base class should know the derived class. That sounds complex but the problem has been solved already:
template<typename DERIVED> class Base
{
public:
class Parameter {
std::string (DERIVED::*get)();
void (DERIVED::*set)();
};
private:
std::list<Parameter> list;
// ...
};
class Derived : public Base<Derived> // !!!
{
registerNew(&Derived::getColor, &Derived::setColor);
};
This solution is known as the Curiously Recurring Template Pattern (CRTP).
I am trying to convert some Python classes into c++ but am having some trouble. I have a Base class which has a class (static) variable and a method which returns it. I also have a derived class which overrides the class (static) variable like so,
In Python:
class Base:
class_var = "Base"
#classmethod
def printClassVar(cls):
print cls.class_var
class Derived(Base):
class_var = "Derived"
d = Derived()
d.printClassVar()
which prints out the desired derived class variable, "Derived". Any idea how I can get the same functionality in c++? I have tried but end up getting the class variable of the Base class.
In c++
class Base
{
public:
static void printStaticVar(){cout << s_var << endl;}
static string s_var;
};
string Base::s_var = "Base";
class Derived : public Base
{
public:
static string s_var;
};
string Derived::s_var = "Derived";
void main()
{
Derived d;
d.printStaticVar();
}
Write a virtual function which returns a reference to the static member:
class Base
{
public:
void printStaticVar() {cout << get_string() << endl;}
static string s_var;
virtual string const& get_string() { return Base::s_var; }
};
string Base::s_var = "Base";
class Derived : public Base
{
public:
static string s_var;
virtual string const& get_string() { return Derived::s_var; }
};
string Derived::s_var = "Derived";
void main()
{
Derived d;
d.printStaticVar();
}
Note that printStaticVar shouldn't be static.
You could also make the string static local inside the getter:
class Base
{
public:
void printStaticVar() {cout << get_string() << endl;}
virtual string const& get_string() {
static string str = "Base";
return str;
}
};
class Derived : public Base
{
public:
virtual string const& get_string() {
static string str = "Derived";
return str;
}
};
void main()
{
Derived d;
d.printStaticVar();
}
Another possibility might be:
class Base
{
const std::string var;
public:
Base(std::string s="Base") : var(s) {}
void printVar() { std::cout << var << std::endl }
};
class Derived : public Base
{
public:
Derived(std::string s="Derived") : Base(s) {}
};