I have base class like this:
class Base{
public:
virtual Base *createNew(){
auto newItem = new Base();
setNew(newItem);
return newItem;
};
void setNew(Base *item){
item->value = value;
};
private:
int value;
};
A number of derived classes are shown below, each of which has a createNew interface that returns a derived object.
class Derive1 : public Base{
Derive1 *createNew(){
auto newItem = new Derive1();
setNew(newItem);
return newItem;
};
void setNew(Derive1 *item){
Base::setNew(item);
item->value1 = value1;
};
private:
int value1;
};
class Derive2 : public Base{
Derive2 *createNew(){
auto newItem = new Derive2();
setNew(newItem);
return newItem;
};
void setNew(Derive2 *item){
Base::setNew(item);
item->value2 = value2;
};
private:
int value2;
};
class Derive3 : public Base{
Derive3 *createNew(){
auto newItem = new Derive3();
setNew(newItem);
return newItem;
};
void setNew(Derive3 *item){
Base::setNew(item);
item->value3 = value3;
};
private:
int value3;
};
int main(int argc, char *argv[])
{
std::list<Base *> list;
list.push_back(new Derive1);
list.push_back(new Derive2);
list.push_back(new Derive3);
list.push_back(new Derive2);
list.push_back(new Derive1);
std::list<Base *> listNew;
for(auto item : list)
{
listNew.push_back(item->createNew());
}
...
//ignore the memory leak.
}
Is there any easy way to not write every createNew in the derived class, because they are similar, the only difference is the type. Do templates help?
Supposedly you want to use the Curiously Recurring Template Pattern (CRTP) for this. Here is an example where we introduce template class BaseT that inherits from Base. Note how each derived class inherits from BaseT passing itself as template parameter.
class Base {
public:
virtual Base* createNew() = 0;
virtual ~Base() {}
};
template <typename T>
class BaseT : public Base {
public:
Base* createNew() override {
return createDerived();
}
T* createDerived() {
auto newItem = new T();
setNew(newItem);
return newItem;
};
void setNew(T* item){
item->value = value;
setNewDerived(item);
};
virtual void setNewDerived(T* item) {}
virtual ~BaseT() {}
private:
int value;
};
class Derive1 : public BaseT<Derive1> {
public:
void setNewDerived(Derive1* item) override {
item->value1 = value1;
}
private:
int value1;
};
class Derive2 : public BaseT<Derive2> {
public:
void setNewDerived(Derive2 *item) override {
item->value2 = value2;
}
private:
int value2;
};
class Derive3 : public BaseT<Derive3> {
public:
void setNewDerived(Derive3 *item) override {
item->value3 = value3;
};
private:
int value3;
};
Is this what you are trying to do?
Related
If I have a class called Node, would it be bad, if objects of the Node class knew their NodeType, and the NodeType would be used to cast to a specific interface like this:
// NodeType
enum class NodeType : uint8_t
{
None = 0,
Foo = 1 << 0,
Bar = 1 << 1,
FooBar = 1 << 2,
FooMask = Foo | FooBar,
BarMask = Bar | FooBar,
};
inline constexpr uint8_t operator&(const NodeType& t_lhs, const NodeType& t_rhs)
{
return static_cast<uint8_t>(t_lhs) & static_cast<uint8_t>(t_rhs);
}
// Base Node Class
class Node
{
public:
virtual NodeType GetNodeType() const = 0;
};
// Interfaces
class IFoo
{
public:
virtual ~IFoo() = default;
virtual void FooSpecificMethod() const = 0;
};
class IBar
{
public:
virtual ~IBar() = default;
virtual void BarSpecificMethod() const = 0;
};
// Derived Node Classes
class FooNode : public Node, public IFoo
{
public:
NodeType GetNodeType() const override { return NodeType::Foo; }
void FooSpecificMethod() const override { std::cout << "Foo.\n"; }
};
class BarNode : public Node, public IBar
{
public:
NodeType GetNodeType() const override { return NodeType::Bar; }
void BarSpecificMethod() const override { std::cout << "Bar.\n"; }
};
class FooBarNode : public Node, public IFoo, public IBar
{
public:
NodeType GetNodeType() const override { return NodeType::FooBar; }
void FooSpecificMethod() const override { std::cout << "Foo.\n"; }
void BarSpecificMethod() const override { std::cout << "Bar.\n"; }
};
// Use of NodeType and Interfaces
std::vector<std::unique_ptr<Node>> GetNodes()
{
std::vector<std::unique_ptr<Node>> nodes{};
nodes.push_back(std::make_unique<FooNode>());
nodes.push_back(std::make_unique<FooNode>());
nodes.push_back(std::make_unique<BarNode>());
nodes.push_back(std::make_unique<FooBarNode>());
nodes.push_back(std::make_unique<FooBarNode>());
nodes.push_back(std::make_unique<FooBarNode>());
return nodes;
}
int main()
{
std::vector<std::unique_ptr<Node>> nodes{ GetNodes() };
for (const auto& node : nodes)
{
if ((node->GetNodeType() & NodeType::FooMask) != 0)
dynamic_cast<const IFoo*>(node.get())->FooSpecificMethod();
}
for (const auto& node : nodes)
{
if ((node->GetNodeType() & NodeType::BarMask) != 0)
dynamic_cast<const IBar*>(node.get())->BarSpecificMethod();
}
}
My goal is to do type specific things on objects in a polymorphic collection like in the last code snippet. Is this a bad approach? Is there any more OO approach to this?
Is this a bad approach? Is there any more OO approach to this?
Yes. You can just dynamic_cast to the appropriate pointer type and check the result is not null.
int main()
{
std::vector<std::unique_ptr<Node>> nodes{ GetNodes() };
for (const auto& node : nodes)
{
if (auto foo = dynamic_cast<const IFoo*>(node.get()))
foo->FooSpecificMethod();
}
for (const auto& node : nodes)
{
if (auto bar = dynamic_cast<const IBar*>(node.get()))
bar->BarSpecificMethod();
}
}
If for some reason you want to avoid dynamic_cast, you can add virtual functions to Node. This is perhaps the "most OO" way.
class Node
{
public:
virtual ~Node() = default;
virtual const IFoo * asFoo() const { return nullptr; }
virtual const IBar * asBar() const { return nullptr; }
};
class FooNode : public Node, public IFoo
{
public:
const IFoo* asFoo() const override { return this; }
void FooSpecificMethod() const override { std::cout << "Foo.\n"; }
};
class BarNode : public Node, public IBar
{
public:
const IBar* asBar() const override { return this; }
void BarSpecificMethod() const override { std::cout << "Bar.\n"; }
};
class FooBarNode : public Node, public IFoo, public IBar
{
public:
const IFoo* asFoo() const override { return this; }
const IBar* asBar() const override { return this; }
void FooSpecificMethod() const override { std::cout << "Foo.\n"; }
void BarSpecificMethod() const override { std::cout << "Bar.\n"; }
};
int main()
{
std::vector<std::unique_ptr<Node>> nodes{ GetNodes() };
for (const auto& node : nodes)
{
if (auto foo = node->asFoo())
foo->FooSpecificMethod();
}
for (const auto& node : nodes)
{
if (auto bar = node->asBar())
bar->BarSpecificMethod();
}
}
I get the compiler error "Use of undeclared identifier '_storage'"
#include <iostream>
struct Storage{
int t;
};
struct DerivedStorage : Storage{
int s;
};
struct DerivedStorage2 : DerivedStorage{
int r;
};
template<typename DS = Storage>
class Base{
public:
DS* _storage = nullptr;
Base(){
_storage = new DS();
}
void m(){
_storage->t++;
}
};
template<typename DS = DerivedStorage>
class Derived : public Base<DS>{
public:
void m2(){
_storage->s++; //error here
}
};
template<typename DS = DerivedStorage2>
class Derived2 : public Derived<DS>{
public:
void m3(){
_storage->r++; //error here
}
};
int main(int argc, const char * argv[]) {
Derived2<DerivedStorage2> t;
for(int i = 0;i<3;i++){
t.m3();
}
return 0;
}
Any idea what the problem is ?
Because Derived itself does not have a member variable named _storage, use this->_storage to access Base's _storage instead.
void m2(){
this->_storage->s++;
}
Demo
i know there is nothing like virtual template method in C++, but as it seems it is exactly what i need. Is there any workaround i could use? I am thankful for any suggestion.
I would like to add Entities to a vector by a add method, which need to be virtual and also template, how to avoid this?
#include <iostream>
#include <vector>
class EntityBase {
public:
};
class EntityDerived1 : public EntityBase {
public:
};
class EntityDerived2 : public EntityBase {
public:
};
class ContainerBase {
public:
template<typename T>
virtual void add() = 0; // i know this is not allowed!!!
};
class ContainerConcrete : public ContainerBase {
public:
template<typename T>
void add() override { // i know this is not allowed!!!
data.push_back(std::make_shared<T>());
}
void doSecretStuffWithDataHere() {
// ...
}
private:
std::vector<std::shared_ptr<EntityBase>> data;
};
class Engine {
public:
Engine() :
container(std::make_shared<ContainerConcrete>())
{}
ContainerBase& getContainer() {
auto rawPointer = container.get();
return *container;
}
private:
std::shared_ptr<ContainerConcrete> container;
};
int main() {
Engine engine;
ContainerBase& container = engine.getContainer();
container.add<EntityDerived1>();
container.add<EntityDerived2>();
}
Just make add a regular virtual function that takes shared_ptr as a parameter
class ContainerBase {
public:
virtual void add(std::shared_ptr<EntityBase>) = 0;
};
class ContainerConcrete : public ContainerBase {
public:
void add(std::shared_ptr<EntityBase> p) override {
data.push_back(p);
}
// . . .
And then invoke it with make_shared for the desired type:
int main() {
Engine engine;
ContainerBase& container = engine.getContainer();
container.add(std::make_shared<EntityDerived1>());
container.add(std::make_shared<EntityDerived2>());
}
Alternatively you can add a templated overload that invokes make_shared:
virtual void add(std::shared_ptr<EntityBase>) = 0;
template<typename T>
void add() {
add(std::make_shared<T>());
}
I have base class and derived class in C++.
I want to determine if the data of the derived class is the same using the pointers of the base class.
enum type
enum class FruitType: int{
Apple,
Orange,
};
base class
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
};
derived class
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
};
initialize
// initialize
std::vector<Base*> fruit_list_ = {
new Apple(42),
new Orange(0.f),
new Apple(1) };
Is there any way to check with HasSameData()?
Base* HasSameData(const Base* pCompare){
for (const auto& list : fruit_list_)
{
if( pCompare->fruit_type == list->fruit_type ){
// how to check same data...?
if( /* ... */ ){
return list;
}
}
}
return nullptr;
}
int main(){
// check same data
Base* pCompare = fruit_list_[2];
if(HasSameData(pCompare)){
// I want to return fruit_list_[2] pointer...
}
}
You could add an abstract method sameData() to the base case
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
virtual bool sameData(const Base& other) const = 0;
};
Override in the derived classes:
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
virtual bool sameData(const Base& other) const {
const Apple* apple = dynamic_cast<const Apple*>(&other);
return apple && apple->foo == foo;
}
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
virtual bool sameData(const Base& other) const {
const Orange* orange = dynamic_cast<const Orange*>(&other);
return orange && orange->bar == bar;
}
};
And use it as follows:
// how to check same data...?
if( pCompare->sameData(*list) ){
The simplest way is to use a virtual function to compare equality and implement the comparison logic in the body of the virtual function.
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
virtual bool Equals(Base *other) const = 0;
};
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
bool Equals(Base *other) const override {
if (other->fruit_type != FruitType::Apple)
return false;
return foo == ((Apple*)other)->foo;
}
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
bool Equals(Base *other) const override {
if (other->fruit_type != FruitType::Orange)
return false;
return bar == ((Orange*)other)->bar;
}
};
Then write your comparison function like this:
bool HasSameData(const Base* pCompare){
for (const Base *fruit : fruit_list_)
if (pCompare->Equals(fruit))
return true;
return false;
}
What I'm trying to achieve is to keep track of what types of objects we're created that inherit from a base class. If a class inherits from the base class but is not instantiated in an object I'm not that interested in tracking that (this condition can be included or not depending if the implementation is easier or not)
Dummy example:
template <typename T>
class Person
{
public:
Person() {
T* x;
container.push_back(x);
}
virtual ~Person() {}
private:
static heterogeneous_container container;
};
class Employee : public Person <Employee>
{
};
class Employee2 : public Employee
{
};
Also, I would like this to work for chained inheritance. Is it possible that when I instantiate an Employee2, the base class Person will add an Employee2 type pointer in the container?
As for the heterogeneous container, I think this can be used link
I think what you want is more like:
class Person
{
public:
Person() {
objects.push_back(this);
}
virtual ~Person() {
objects.erase(this);
}
private:
static std::set<const Person*> objects;
};
class Employee : public Person
{
};
class Employee2 : public Employee
{
};
With this approach, you can enquire the dynamic type of the most-derived object that each of the pointers in the container points to.
Note that the objects set has to contain the pointers, not the type_info for each object. The problem is that inside the constructor for the Person sub-object of an Employee2 object, the most-derived type of *this will be Person, not Employee2 (it won't become Employee2 until execution enters the Employee2 constructor).
More or less, I have somewhere working like that :
#include <iostream>
#include <functional>
#include <vector>
struct ClassEntry {
size_t id = 0;
const char* label;
};
class BaseClass {
public:
protected:
static void RegisterType(size_t id, const char * label) {
ClassEntry entry;
entry.id = id;
entry.label = label;
mRegisteredTypes.emplace_back(entry);
std::cout << "Registered type " << id << " label " << label << std::endl;
}
static size_t createId() {
static size_t id = 0;
return id++;
}
static std::vector<ClassEntry> mRegisteredTypes;
};
std::vector<ClassEntry> BaseClass::mRegisteredTypes;
class OneTimeCall {
public:
OneTimeCall(std::function<void(void)>&& func) {
func();
}
virtual ~OneTimeCall() {
}
};
template<typename T>
class MyClass : public BaseClass {
public:
MyClass() {
static OneTimeCall one_time {
[this]{
BaseClass::RegisterType(GetId(), T::GetType());
}
};
}
private:
protected:
static size_t GetId() {
static size_t id = BaseClass::createId();
return id;
}
};
class A : public MyClass<A> {
public:
A() {
}
static const char *GetType() {
return "ClassA";
}
};
class B : public MyClass<B> {
public:
B() {
}
static const char *GetType() {
return "ClassB";
}
};
int main() {
A a;
B b;
A a2;
B b2;
return 0;
}
The output is :
Registered type 0 label ClassA
Registered type 1 label ClassB
The main idea is to use CRTP and static initialization in construction for register each type only one time. It works without problems in linux, on windows compiler the static BaseClass ID is new on each DLL, so you need to tune a bit for use in a external library.
With this approach you dont need any external library and is possible to compile without rtti.
For inheritance you can create a new class:
template<typename Current, typename Base>
class Mix : public MyClass<Current>, public Base {};
So if you pass "type C" as current type (CRTP) and type A as base class can work.
class C : public Mix<C, A> {
public:
C() {
}
static const char *GetType() {
return "ClassC";
}
};
With this approach if you have previously registered "A" it will not be registered again, and if you dont have "A" it will be registered after "C".
One way to track objects is to store them an intrusive list and embed a link node into the objects. This provides noexcept guarantee for tracker operations and doesn't require an extra memory allocation when inserting the elements into the tracker container, for the price of an embedded list node (two pointers) in each tracked object:
#include <iostream>
#include <boost/intrusive/list.hpp>
namespace bi = boost::intrusive;
template<class T>
class Tracker : public bi::list_base_hook<bi::link_mode<bi::auto_unlink>>
{
protected:
static bi::list<Tracker, bi::constant_time_size<false>> objects_;
Tracker() noexcept { objects_.push_back(*this); }
Tracker(Tracker const&) noexcept { objects_.push_back(*this); }
public:
static auto count() noexcept { return objects_.size(); }
};
template<class T>
bi::list<Tracker<T>, bi::constant_time_size<false>> Tracker<T>::objects_;
struct Employee : Tracker<Employee> {};
struct Employee2 : Employee {};
int main() {
std::cout << Tracker<Employee>::count() << '\n';
{
Employee e0;
Employee2 e1;
std::cout << Tracker<Employee>::count() << '\n';
}
std::cout << Tracker<Employee>::count() << '\n';
}
Outputs:
0
2
0
Tracker without Boost library:
struct AutoListNode {
AutoListNode *next_ = this, *prev_ = this;
AutoListNode() noexcept = default;
AutoListNode(AutoListNode const&) = delete;
AutoListNode& operator=(AutoListNode const&) = delete;
~AutoListNode() noexcept { this->erase(); }
void push_back(AutoListNode* node) noexcept {
auto prev = prev_;
node->prev_ = prev;
node->next_ = this;
prev->next_ = node;
prev_ = node;
}
void erase() noexcept {
auto next = next_;
auto prev = prev_;
prev->next_ = next;
next->prev_ = prev;
}
size_t size() const noexcept {
size_t count = 0;
for(auto node = next_; node != this; node = node->next_)
++count;
return count;
}
};
template<class T>
class Tracker : private AutoListNode
{
protected:
static AutoListNode objects_;
Tracker() noexcept { objects_.push_back(this); }
Tracker(Tracker const&) noexcept { objects_.push_back(this); }
public:
static auto count() noexcept { return objects_.size(); }
};
template<class T>
AutoListNode Tracker<T>::objects_;