加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

C 11模板变量设计

发布时间:2020-12-16 10:34:41 所属栏目:百科 来源:网络整理
导读:我有很多抽象类字母的子类,如A,B,C,D等.字母有一个整数ID变量,并且Letter的每个子类都被赋予一个唯一的id. 然后我有另一个班,称之为Alphabet.字母表有一个 listshared_ptrLetter 会员.这是问题…我想优雅地将B和C或其他子类的Letter添加到字母的特定实例中.
我有很多抽象类字母的子类,如A,B,C,D等.字母有一个整数ID变量,并且Letter的每个子类都被赋予一个唯一的id.

然后我有另一个班,称之为Alphabet.字母表有一个

list<shared_ptr<Letter>>

会员.这是问题…我想优雅地将B和C或其他子类的Letter添加到字母的特定实例中.我认为最方便的方法是以某种方式使用子类的整数id.换句话说,我希望能够有像Alphabet.addLetter(int id)这样的东西,所以如果我做了alphabet1.add(14),它会以某种方式将H类的shared_ptr添加到列表中.

有没有一种优雅的方法来做到这一点,避免一些巨大的if语句,我需要不断更新每次添加或删除B,D,E等类之一?我希望有一些模板解决方案,但我不熟悉工厂和模板等高级c概念.我想要的天真的东西是某种矢量/地图,它将我的ID转换为类名,这样我就可以做类似的事情

list.push_back(shared_ptr<classVector(i)>(new classVector(i))

或类似的东西,虽然我不知道这是否可能.

谢谢!

附:我刚刚选择了Alphabet示例,因为我不想给出不必要的细节.显然,我不是试图以这种愚蠢的方式设计字母表,哈哈.

编辑:我正在努力使这有意义.我的目标是能够以最小的努力快速创建Letter的新子类.我想避免输入看起来像……的代码

list.push_back(shared_ptr<X>(...));

每次我写一封新信.这有意义吗?

解决方法

如果我正确地理解你,使用所谓的工厂模式,这相对容易.

如果您可以列出所有派生类型:

信头:

struct Letter {
    enum LetterEnum {LetterA,LetterB,LetterC,LetterCount};

    virtual ~Letter() {} //base types should always have virtual destructor
    virtual void foo() = 0;

    static std::unique_ptr<Letter> construct(LetterEnum c);
};

实施标题:

struct A : Letter {
  void foo() override;
};

struct B : Letter {
  void foo() override;
};

struct C : Letter {
  void foo() override;
};

信体:

std::unique_ptr<Letter> Letter::construct(Letter::LetterEnum c) 
{
    switch(c) {
    case Letter::LetterA : return make_unique<A>();
    case Letter::LetterB : return make_unique<B>();
    case Letter::LetterC : return make_unique<C>();
    default: throw ...;
    }
}

用法:

int main() {
    char c;
    std::cin >> c;
    //get a letter of the derived type associated with the letter entered
    std::unique_ptr<Letter> ptr = Letter::construct(c);    
}

如果您无法列出所有派生类型:

允许派生类型使用Letter类注册自己,然后Letter可以使用它来创建每个派生类型.这样,添加和删除派生类型不会更改任何其他文件.简单!

struct Letter {
    virtual ~Letter() {} //destructor is always virtual when inheretence is involved
    ....
    //this is a "shared" function in the Letter class itself
    //it takes a letter,and returns a dynamically allocated instance
    //of the derived type corresponding with that letter
    static std::unique_ptr<Letter> construct(char c);
    //this typedef represents the actual function that returns 
    //each dynamically allocated derived type
    typedef std::function<std::unique_ptr<Letter>()> letter_ctor;
    //this is a "shared" function in the Letter class itself
    //it takes a letter,and a function that creates derived types,//and saves them inside the container ctors
    static bool register(char c,letter_ctor func);
private:
    //this is a "shared" member in the Letter class.  
    //There is only one shared by all of the Letters.  Like a global.
    //When you give it a letter,it gives you a function.
    //and is VERY fast for large numbers of entries
    static std::unordered_set<char,letter_ctor> ctors;
};

并在您的实现文件中:

//here's the function that derived types register themselves with
//pretty straightforward,just inserts the pair into the unordered_map
bool Letter::register(char c,Letter::letter_ctor func)
{return Letter::ctors.insert(std::make_pair(c,std::move(func))).second;}

//and here's the function that creates the derived types
//it checks if the letter is in the unordered_map
//if the letter isn't there,it throws an exception
//otherwise,it calls the function associated with that letter
//which creates the derived type on the heap,and returns a pointer to it
std::unique_ptr<Letter> Letter::construct(char c) 
{
     auto it = Letter::ctors.find(c);
     if (it == Letter::ctors.end())
         throw ...;
     return it->second(); //construct that letter
}

然后你的派生类型执行此操作:

//you know this part
struct LetterA : public Letter 
{
   ....
};
//derived types have to register themselves:
//this is a global,so when the program loads,it automatically calls this
//even before main runs*
//it registers the letter 'A' and a function that creates a LetterA class on the heap
static bool registerA = Letter::register('A',[](){return make_unique<LetterA>();});

然后你可以轻松创建arbirary派生类型!

int main() {
    char c;
    std::cin >> c;
    //get a letter of the derived type associated with the letter entered
    std::unique_ptr<Letter> ptr = Letter::construct(c);
}

*它并不总是在main之前被调用.如果你有问题,请加一个bool init_A();在A头文件中,并在A实现文件中bool init_A(){return true;},并在主文件中有静态bool AInit = init_A();应该强迫它.但这在实践中几乎从不需要.

作为旁注,这些取决于有一个make_unique,它应该在C 11中,但由于疏忽而被遗漏.它将在C 14中.与此同时,使用:

template<class T,class...Us>
std::unique_ptr<T> make_unique(Us&&...us) 
{return std::unique_ptr<T>(new T(std::forward<Us>(us)...));}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读