Проблема объявления объектов класса вне условного оператора из-за функции шаблона - PullRequest
2 голосов
/ 16 марта 2011

Для моего класса c ++ нам было поручено написать класс шаблона, тип объекта класса которого определяется пользователем с использованием шаблонов.

Фрагмент кода из main:

if (dataType == "1" || dataType == "int") {  
    simpleVector<int> userArray;  
} else if (dataType == "2" || dataType == "double") {  
    simpleVector<double> userArray;  
} else if (dataType == "3" || dataType == "char") {  
    simpleVector<char> userArray;  
} else if {  
    simpleVector<string> userArray;  
}  
userArray.setDefaultArray();

Fromэто я получаю код ошибки C2065 - необъявленный идентификатор ошибка.Я понимаю, почему я получаю ошибку, но я не знаю, как я могу объявить userArray, прежде чем я знаю тип данных.

Исходный код:

#include <stdio.h>
#include <string>
using std::string;
#include <iostream>
using std::cout;
using std::cin;
using std::endl;

template<class T>
class simpleVector {
public:
    void setDefaultArray ();
    void setArraySize (int size);
    void copy (T *arr);
    void desctruct ();
    int getArraySize ();
    T getElementAt (int index);
    void fillArray();
private:
    int arraySize;
    T *myArray;
};

int main () {
    string dataType;
    int arraySize;
    bool loopCondition = false;

    do {
        cout << "Data Type:"; 
        cin >> dataType;
        if (dataType == "1" || dataType == "2" || dataType == "3" || dataType == "4" 
        || dataType == "int" || dataType == "double" || dataType == "char" || dataType == "string") {
            loopCondition = false;
        } else {
            cout << "WARNING: invalid data type entered." << endl;
            cout << "Valid entries are (1.int, 2.double, 3.char, 4.string)" << endl;
            loopCondition = true;
        }
    } while (loopCondition);

    if (true) 
        int num = 9;
    else
        int num = 7;

    int num2 = num;

    //simpleVector userArray; //?? Review

    if (dataType == "1" || dataType == "int") {
        simpleVector<int> userArray;
    } else if (dataType == "2" || dataType == "double") {
        simpleVector<double> userArray;
    } else if (dataType == "3" || dataType == "char") {
        simpleVector<char> userArray;
    } else if (dataType == "4" || dataType == "char") {
        simpleVector<string> userArray;
    }
    userArray.setDefaultArray();
    cout << "Number of Inputs:"; 
    cin >> arraySize;
    userArray.setArraySize(arraySize);
    userArray.fillArray();

    return 0;
}

//Should call desctruct before this if reusing.
template<class T>
void simpleVector<T>::setDefaultArray() {
    arraySize = 0;
    myArray = NULL; //note: NULL is case sensitive (#include <stdio.h>)
}

template<class T>
void simpleVector<T>::setArraySize (int size) {
        myArray = new T[size];
}

template<class T>
void simpleVector<T>::copy (T *arr) {
//ToDo
}

template<class T>
void simpleVector<T>::desctruct () {
//ToDo
}

template<class T>
int simpleVector<T>::getArraySize () {
//ToDo
}

template<class T>
T simpleVector<T>::getElementAt (int index) {
//ToDo
}

template<class T>
void simpleVector<T>::fillArray() {
    cout << "Enter Array Values" << endl;
    for (int i; i < arraySize; i++) {
        cout << "Element " + i + ":";
        cin >> myArray[i];
    }
}

Спасибо,

Mike

Ответы [ 3 ]

2 голосов
/ 16 марта 2011

Код в ответе Евгения выглядит великолепно, но, возможно, слишком сложен для изучения C ++?

Очень простое решение может выглядеть следующим образом

  • объявляет класс vectorBase, который объявляетвсе методы, которые вам нужны во всех ваших векторах
  • пусть шаблонный класс наследует от vectorBase

шаблонный класс simpleVector: public vectorBase {...

  • затем объявите указатель типа vectorBase перед вашим

if (dataType == "1" || dataType == "int") ...

  • в блоке if назначьте вновь созданный userArrays указателю базового класса
  • , позже получите доступ к методам через указатель baseClass, который идентичен для всех определенных классов шаблонов
0 голосов
/ 17 марта 2011

Как я понимаю, цель этой проблемы - научить, как использование шаблона ограничено определением типа во время компиляции.Довольно просто, что выбор пользователя будет ограничен некоторым списком типов, которые разработчик хотел явно указать.Теперь вопрос - как это влияет на результирующую программу?

Во-первых, вы должны понимать, что пути кода для всех возможных значений аргумента шаблона будут созданы во время компиляции.Другими словами, двоичный код для setDefaultArray, setArraySize, fillArray и других функций-членов, которые вы явно или неявно вызываете в своем универсальном алгоритме, будет сгенерирован для int, double, char и std::string аргументы шаблона.Вы ничего не можете сделать, чтобы оптимизировать его из исполняемого файла.

Однако вы можете решить, как наиболее эффективно хранить ваши объекты в памяти.И, очевидно, для вашей задачи вам нужен только один экземпляр simpleVector за раз.Таким образом, вы можете подумать о блоке памяти, достаточно большом для того, чтобы сохранить инстанцирование simpleVector, а также указать, какой из них он в данный момент содержит.В C ++ это будет звучать так:

struct SimpleVectors {
    VectorTypeEnum vte;
    union {
        simpleVector<int> v_int;
        simpleVector<double> v_double;
        simpleVector<char> v_char;
        simpleVector<string> v_string;
    };
};

Обратите внимание, что вы можете делать это только с POD-структурами (определение в google).Подходы, основанные на наследовании, в конечном итоге сводятся к такой компоновке.

Чтобы завершить картину, нам просто нужно подключить логику обработки к этой структуре данных:

template <
    typename T
>
inline void handleTask (
    simpleVector <
        T
    >
        & v
)
{
    int arraySize;
    v.setDefaultArray();
    cout << "Number of Inputs:"; 
    cin >> arraySize;
    v.setArraySize(arraySize);
    v.fillArray();
}

Преимуществоэтот подход, основанный на наследовании, заключается в том, что вы можете сделать свои функции-члены класса встроенными, и компилятор позаботится о том, чтобы их вызовы были на порядок быстрее, чем функции виртуальных членов.

И, наконец,ключевой элемент вашей main функции будет выглядеть так:

SimpleVectors userArray; 
// we don't really need to initialize userArray.vte in this sample

if (dataType == "1" || dataType == "int") {
    handleTask(userArray.v_int);
} else if (dataType == "2" || dataType == "double") {
    handleTask(userArray.v_double);
} else if (dataType == "3" || dataType == "char") {
    handleTask(userArray.v_char);
} else if (dataType == "4" || dataType == "string") {
    handleTask(userArray.v_string);
}
0 голосов
/ 16 марта 2011

Вы не можете сделать это, потому что определение типов - процесс компиляции. Используйте наследование вместо шаблонов, если вы хотите определять типы во время выполнения. Также могу предложить вам вариантный вариант. Например:

#include <memory>
#include <string>

class variant
{
public:

    template <class T>
    variant& operator = (T const& t)
    {
        typedef type<T> assign_type;
        object = std::auto_ptr<assign_type>(new assign_type(t));
        return *this;
    }

    template <class T>
    operator T ()
    {
        typedef type<T> assign_type;
        assign_type& type = dynamic_cast<assign_type&>(*object);
        return type.get();
    }

private:

    class base
    {
    public:

        virtual ~base() {}
    };

    typedef std::auto_ptr<base> base_ptr;

    template <class T>
    class type : public base
    {
    public:

        type(T const& t)
        : object(t)
        {
        }

        T get() const
        {
            return object;
        }

    private:

        T object;
    };

    base_ptr object;
};

struct dummy
{
    int a;
    int b;
    int c;
};

int main()
{
    variant v1, v2, v3, v4;

    v1 = 2;
    v2 = 5.0f;
    v3 = std::string("Pot of gold");
    v4 = dummy();

    int         i = v1;
    float       f = v2;
    std::string s = v3;
    dummy       d = v4;

    return 0;
}
...