对基类和派生类使用静态容器 [英] using Static Container for base and derived classes

查看:120
本文介绍了对基类和派生类使用静态容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图建立一个[ base +派生]类的对象容器( std :: map 是准确的),这将是一个静态变量,嵌入在Base类中,以便每个其他对象或者派生自它,或者从它的子类,最多只有1个列表。如果没有创建对象,我仍然可以通过其他友好(静态)函数访问该列表。



这里是代码 -

  #include< iostream> 
#include< string>
#include< unordered_map>

class A {

std :: string id;
static std :: unordered_map< std :: string,A *>列表;

public:

(std :: string _i):id(_i){}
static void init(){
// doSomeProcessing或者让我们现在调用clear()
list.clear();
}
static void place(std :: string _n,A * a){
list [_n] = a;
}
virtual void doSomething(){std :: cout< DoSomethingBase\\\
;}
};

std :: unordered_map< std :: string,A *> A :: list = {};

class B:public A {

std :: string name;

public:

B(std :: string _n):name(_n),A(_n){}
void doSomething(){std :: cout < DoSomethingDerived\\\
;}
};


int main(){
A :: init();
A :: place(b1,new B(b1));
A :: place(a1,new A(a1));
return 0;
}

代码编译成功,但是我有两件事情,

- 指针作为 std的值:

:map
?我相信我完全没有抓住他们,但我正在努力学习。我知道他们不是在这里删除,但我该怎么办呢?在析构函数中?或让程序完成.....(坏,对吧?)



轻微 - 使用静态成员?我从人们听说静态变量是坏的一些未知的原因,不应该使用,除非必要的。他们甚至从一些早期版本的cpp中删除。是对的吗?但是,我的选择是什么,然后...创建它 main()




假设我有一个员工更具体的工作,例如 editor writer developer 仍然来自员工。但是,也可能存在基类 employee 的实例,因为可能有员工没有cateogrised,但会很快。


我们假设这是一个要求,虽然我可以改变。我使用静态 std :: map ,所以只需要它的一个实例,它是统一的所有base +派生类。

解决方案

少数:使用托管指针。这是您的代码的修改版本基于 unique_ptr

  A {
// ...
static std :: unordered_map< std :: string,std :: unique_ptr< A>列表;

// ...
template<类T,类... Args>
static
//通过返回类型只允许基于A的对象T
typename std :: enable_if< std :: is_base_of< A,T> :: value> :: type
place(std :: string _n,Args& ... args)
{
list.emplace(_n,std :: make_unique< T>(std :: forward& (args)...));
}
// ...
};

std :: unordered_map< std :: string,std :: unique_ptr< A>> A :: list = {};

class B:public A {

// ...
//在此处更正警告:基础应在成员之前构建
B std :: string _n):A(_n),name(_n){}
// ...
};

int main(){
A :: init();
A :: place< B>(b1,b1);
A :: place< A>(a1,a1);
//可能,第二个参数现在是多余的
//可以删除它并调用到位
// std :: make_unique< T>(_ n,std :: forward& ;(args)...)
return 0;
}

我修改使用 make_unique 这是C ++ 14,你可以使用 new T {std :: forward< Args> (args)...} 。新的 place 函数是一个可变参数模板遵循 make_unique 原型。



如Adam Martin的评论所示, enable_if 可用于限制类型 T 到继承 A 的对象。



Jarod42,则应使用转发参考来尊重调用<$时传递的值类别c $ c> place



我使用 emplace 而不是 operator [] 复制或移动操作。



另一个选择是使用 shared_ptr 。实施方式类似。


I'm trying to build a [base+derived] class's object container(std::map to be accurate) which would be a static variable, embedded inside Base class so that every other object either derived from it, or from it's child classes would've only 1 list at most. Also if no object is created, I still would've access to that list through other friendly(static) functions.

Here's the code -

#include <iostream>
#include <string>
#include <unordered_map>

class A{

    std::string id;
    static std::unordered_map<std::string, A*> list;

  public:

    A(std::string _i): id(_i){}
    static void init(){
        // doSomeProcessing or let's just call clear() for now
        list.clear();
    }
    static void place(std::string _n, A* a){
        list[_n] = a;
    }
    virtual void doSomething(){std::cout << "DoSomethingBase\n";}
};

std::unordered_map<std::string, A*> A::list = {};

class B : public A{

    std::string name;

  public:

    B(std::string _n):name(_n), A(_n){}
    void doSomething(){std::cout << "DoSomethingDerived\n";}
};


int main() {
    A::init();
    A::place("b1", new B("b1"));
    A::place("a1", new A("a1"));
    return 0;
}

The code compiles successfully however, there are two things at top of my mind, which I might be doing wrong, one major and another minor problem.

Major - Pointers as values to std::map? I'm sure I've totally not grasped them yet, but I'm studying hard. I know they aren't being deleted here, but how should I do it? In the destructor? or let the program finish.....(bad, right?)

Minor - Using static members? I've heard from folks that static variables are bad for some unknown reasons and shouldn't be used unless necessarily required. They were even removed from some early version of cpp. Is that right? But what would be my options then... creating it in main().

Any other mistake I might be doing here.


Edit - I'm supplying a sample scenario so to clear my intentions with following example.

Let's say I've an employee class and some more specific jobs eg editor, writer, developer that are still derived from employees. However there might exist instance of base class employee too, since there might be employees who aren't cateogrised yet, but will be soon.

Let's say this is an requirement, although I'm open to changes. I'm using that static std::map so that only one instance of it is required which is uniform across all base + derived classes. I'm not so familiar with singleton pattern and such but I'll happily learn it in future.

解决方案

Major: use managed pointers. Here is a modified version of your code based on unique_ptr:

class A{
    // ...
    static std::unordered_map<std::string, std::unique_ptr<A>> list;

    // ...
    template< class T, class... Args >
    static
    // enable only A-based objects for T via the return type
    typename std::enable_if<std::is_base_of<A, T>::value>::type
    place(std::string _n, Args&&... args)
    {
        list.emplace(_n, std::make_unique<T>(std::forward<Args>(args)...));
    }
    // ...
};

std::unordered_map<std::string, std::unique_ptr<A>> A::list = {};

class B : public A{

    // ...
    // corrected a warning here: bases should be constructed before members
    B(std::string _n):A(_n), name(_n){}
    // ...
};

int main() {
    A::init();
    A::place<B>("b1", "b1");
    A::place<A>("a1", "a1");
        // maybe, the second argument is now redundant
        // you can remove it and call in place
        // std::make_unique<T>(_n, std::forward<Args>(args)...)
    return 0;
}

I modified place to make it care of the allocation -- using make_unique which is C++14, you can use new T{std::forward<Args>(args)...} instead. The new place function is a variadic template to follow make_unique prototype.

As suggested in the comments by Adam Martin, enable_if can be used to restrict the type T to objects inheriting A.

As edited by Jarod42, you should use forward references to respect the value category passed when calling place.

I used emplace instead of operator[] to avoid unnecessary copy or move operations.

An other option is to use shared_ptr if you need to make a copy of the pointer. The implementation would be similar.

这篇关于对基类和派生类使用静态容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆