如何根据用户输入设置矢量类型

时间:2016-01-13 12:40:41

标签: c++ vector

我想避免为不同类型编写整个程序。这就是代码现在的样子:

switch(e) {
    case('i'): {            // if the user wants integers:
        std::vector<long double> v(b);
        std::cout << "\nEnter the Minimum Size for the numbers: ";
        std::cin >> c;
        std::cout << "\nEnter the Maximum Size for the numbers: ";
        std::cin >> d;
        for (i = 0; i <= b-1; i++)
            a[i] = random_int(c, d);
        .
        .
        .
        sort(a.data(), 0,b-1);
        break;
    }

    case('d'): {           // if the user wants decimal numbers:
        std::vector<long double> v(b);
        std::cout << "\nEnter the Minimum Size for the numbers: ";
        std::cin >> m;
        std::cout << "\nEnter the Maximum Size for the numbers: ";
        std::cin >> n;
        for (i = 0; i <= b-1; i++)
            a[i] = random_float(m, n);
        .
        .
        .
        sort(v.data(), 0,b-1);
        break;
    }

    default: {
        goto loop;
        break;
    }
}

正如你所看到的,这是不必要的长。

更改矢量的类型似乎不起作用(以困难的方式倾斜)并且由于random_int / random_float部分我无法创建矢量函数(他们使用std::uniform_int_distributionstd::uniform_real_distribution)。

2 个答案:

答案 0 :(得分:1)

有很多方法可以做到这一点,而且没有一种“最佳方式”。但最直接的方法可能是使用继承。根据每个行为的类型和实现函数,列出必须更改的所有行为。多态地实现它们。例如:

class IntOrDouble
{
    public:
    bool isInt() const { return _isInt; }
    bool isDouble() const { return !_isInt; }
    int getAsInt() const; // throws if not integer
    double getAsDouble() const; // throws if not double

    protected:
    bool _isInt;
    int _valueIfInt;
    double _valueIfDouble;
};

class VectorOfIntsOrDoubles
{
    public:

    void makeVectorOfInts(); // must be empty
    void makeVectorOfDoubles(); // must be empty

    // Reads an IntOrDouble of the appropriate type for this container
    IntOrDouble ReadValue() const;

    // Generates a random IntOrDouble of the appropriate type for this container
    IntOrDouble GenRandom() const;

    private:
    bool _isInts;
    std::vector <IntOrDouble> _vector;
};

等等。

答案 1 :(得分:0)

另一种多态方法。首先,我们定义一个抽象基类,这是程序的大多数部分才会知道的。它仅定义数据的访问函数,不包含任何(kind类型标记除外)。派生类的大多数访问函数实现只是在运行时抛出,除了适用于元素数据类型的那些:

/// The type which will alwys be returned
class VecHolder
{
    public:
    enum kindE { INTVEC, DBLVEC, /*...*/} ;

    kindE kind;

    VecHolder(kindE k) : kind(k) {}

    /// These expose the vectors for simplicity. The derived classes
    /// will hold just one of them.
    virtual vector<int> &intVec() = 0;
    virtual vector<double> &dblVec() = 0;
    // ...

    static VecHolder *MakeVec(kindE kind);
};

现在我们将展示两个具体的实现,对于double和for int:

/// An implementation for int elements
class IntVecHolder: public VecHolder
{
    public:

    IntVecHolder() : VecHolder(INTVEC) {} 
    vector<int> &intVec() { return vec; };
    vector<double> &dblVec()  { throw exception();}

    protected:
    vector<int> vec;

};

/// An implementation for double elements
class DblVecHolder: public VecHolder
{
    public:

    DblVecHolder() : VecHolder(DBLVEC) {} 

    vector<int> &intVec() { throw exception();}
    vector<double> &dblVec(){ return vec; };

    protected:
    /// This is the actual data (somewhat) hidden behind the 
    /// abstract VecHolder interface.
    vector<double> vec;
};

现在我们知道了这些类,我们可以编写工厂函数,根据用户的选择(kind)创建适当的VecHolder实现:

/// The factory function: Exact type of object behind returned
/// pointer dpends on parameter, but they are all derived from VecHolder
VecHolder *VecHolder::MakeVec(kindE kind)
{
    switch(kind)
    {
        case INTVEC: return new IntVecHolder; break;
        case DBLVEC: return new DblVecHolder; break;
    }
}

最后,这是一个示例用法。我发现它比我想象的更尴尬 - 用户代码总是必须根据持有者的kind进行区分。当然,人们应该隐藏在功能中的丑陋转换。

int main()
{
    /// An array of vec holder pointers
    VecHolder *vecHolders[] 
        {   VecHolder::MakeVec(VecHolder::DBLVEC),
            VecHolder::MakeVec(VecHolder::INTVEC)
        };

    for( auto &vhp: vecHolders )
    {
        // we always have to discriminate.
        switch(vhp->kind)
        {
            case VecHolder::DBLVEC: vhp->dblVec().push_back(1.0); break;
            case VecHolder::INTVEC: vhp->intVec().push_back(2); break;
        }
    }

    for( auto &vhp: vecHolders )
    {
        switch(vhp->kind)
        {
            case VecHolder::DBLVEC: 
                cout << vhp->dblVec()[0] << endl; 
            break;
            case VecHolder::INTVEC: 
                cout << vhp->intVec()[0] << endl; 
            break;
        }

        // clean up
        delete vhp; 
    }
}

示例会话:

$ g++ -std=c++11 -o polymorphic-vec polymorphic-vec.cpp && ./polymorphic-vec
1
2