C ++映射包含任何类型的模板类对象

时间:2018-03-09 10:33:42

标签: c++ templates inheritance stl virtual-functions

我正在编写一个代码,我们需要几种堆栈。像stack<int>, stack<vector<int>>, stack<map<int, string>>, stack<vector<vector<int>>

我有一个基类,其中包含一个虚函数foo(...参数列表...)。此基类被用作多个派生类的父类,其foo()适用于不同类型的堆栈。因此derived1可能正在使用stack<int>而derived2可能正在使用stack<vector<vector<int>>,依此类推在各自的foo()中。

现在我将所有堆栈传递给所有foo函数。因此,每次实现新堆栈时,我的foo()定义必须在base和ALL派生类中再插入一个堆栈类型。

所以例如,最初我只有一个派生类我的基础和派生类就像

class Base
{
     public:
        void foo(stack<int>) = 0;
} 

class Derived : public Base
{
     public:
        void foo(stack<int>)
        {
            ...
            ...
        }
}

现在,假设使用stack<vector<int>>来设置新的派生类。我需要将我的Base和所有派生类foo()更新为

void foo(stack<int> a, stack<vector<int> b)
{
     ....
     ....
}

而我现在想要实现的是我创建了一个包含各种堆栈的StackWrapper类,我可以使用不同的密钥来处理不同的堆栈。

这样的东西
class StackWrapper
{
      stack<int> derived1;
      stack<vector<int>> derived2;
     some-return-type operator[](char ch)
     {
        switch(ch)
        {
            case 'a': return derived1;break;
            case 'b': return derived2;break;
        }
     }
}

通过这种方式,我只需要在这个stackwrapper类中添加一个新的堆栈类型对象,然后在不同的派生类'foo()中使用stackWrapperObj['a']stackWrapperObj['b']之类的东西。

是否有任何方法可以允许这样的类设计。

注意: - 我不希望在foo()中进行任何转换,例如返回void*然后再转换它而不是我想以某种方式返回一个转换对象,具体取决于我分配的各种键不同的堆栈类型。这样我就可以进行像

这样的操作了
stack<int> a = stackWrapperObject['a'];
stack<vector<int>> b = stackWrapperObject['b'];

2 个答案:

答案 0 :(得分:1)

为什么还要努力写operator[]

struct StackWrapper
{
    stack<int> a;
    stack<vector<int>> b;
}

void Derived::foo (StackWrapper & stacks)
{
    stack<int> a = stacks.a;
    stack<vector<int>> b = stacks.b;
    // ... 
}

此时你可能不需要那些当地人,只需直接使用stacks.a

答案 1 :(得分:0)

尝试使用访客模式:使用凯撒班次的基本非模板示例:

<强>的main.cpp

#include <iostream>
#include <fstream>
#include <string>

#include "CaesarShift.h"

int main() {
    std::string filename;
    std::cout << "Please enter the name of the input file. ";
    std::cin >> filename;

    std::ifstream fileIn;
    std::string   text;

    fileIn.open( filename );
    if ( !fileIn.is_open() ) {
        std::cout << "Failed to open file: " << filename << "." << std::endl;
    }

    fileIn >> text;
    fileIn.close();

    CaesarText caesarText;
    caesarText.addText( text );


    std::cout << "Contents of the Caesar Text before peforming a Caesar Shift:\n"
        << caesarText << std::endl;

    int amount = 0;
    std::cout << "Please enter the amount to shift the text ";
    std::cin >> amount;
    std::cout << "Now performing the Caesar Shift: " << std::endl;

    caesarShift( caesarText, amount );

    std::cout << "Caesar Text after performing a Caesar shift:\n"
        << caesarText << std::endl;

    std::ofstream fileOut;
    fileOut.open( std::string( "shifted_" + filename ) );
    if ( !fileOut.is_open() ) {
        std::cout << "Failed to open shifted_" << filename << std::endl;
    }
    fileOut << caesarText.shiftedText() << std::endl;
    fileOut.close();

    system( "PAUSE" );
    return 0;
}

<强> CaesarShift.h

#ifndef CAESAR_SHIFT_H
#define CAESAR_SHIFT_H

class CaesarText {
    std::string _originalText;
    std::string _shiftedText;

public:
    CaesarText() = default;
    explicit CaesarText( const std::string& text ) :
        _originalText( text ) {}

    void addText( const std::string& text ) {
        _originalText = text;
    }

    std::string originalText() const {
        return _originalText;
    }

    std::string shiftedText() const {
        return _shiftedText;
    }

    friend void caesarShift( CaesarText& c, int amount );

    friend std::ostream& operator<<( std::ostream& out, const CaesarText& ceasarText );
};

#endif // !CAESAR_SHIFT_H

<强> CaesarShift.cpp

#include "CaesarShift.h"
#include <string>
#include <iostream>
#include <algorithm>

std::ostream& operator<<( std::ostream& o, const CaesarText& c ) {
    o << "Original Text: " << c._originalText << "\n";
    o << "Shifted Text: " << c._shiftedText << "\n";
    return o;
}

void caesarShift( CaesarText& text, int amount ) {
    // Bound amount to the number of characters in the alphabet
    amount %= 26;

    // Three Different Ways To Perform The Shift //
    /*for ( std::size_t i = 0; i < text._originalText.length(); i++ ) {
        char c = text._originalText[i] + amount;
        text._shiftedText += c;
    }*/

    for ( auto& c : text._originalText ) {
        text._shiftedText += c + amount;
    }

    /*std::transform( text._originalText.begin(), text._originalText.end(),
                std::back_inserter( text._shiftedText ),
                [amount]( unsigned char c ) -> unsigned char { return c + amount; }
    );*/

}

输入:test.txt

Hello

控制台&amp;文件输出 - 根据用户输入的移位量:

// Shift by 2
Original Text: Hello
Shifted Text: Jgnnq

// Shift by 3
Original Text: Hello
Shifted Text: Khoor

// Shift by 29 (29 % 26) = 3
Original Text: Hello
Shifted Text: Khoor

如果查看上面的类,它只存储两个字符串。它确实有构造函数和函数来返回两个私有成员。将班次应用于CaesarText的实现与类或容器本身是分开的。重载操作符也可以轻松地将此对象发送到输出流。

在这种特殊情况下,函数caeserShift()引用了一个CaesarText和一个int。现在,此独立函数执行operations or calculations上的实际class object。这里唯一特别的是caesarShift()CaesarText的朋友,使其能够直接访问成员,这样您就不必拥有getters并创建不需要的额外临时和副本。最后,algorithm caesarShift()不是CeasarText的成员,而是对其进行操作。整个带有容器和迭代器的标准库使用相同的模式。