2016-09-29 3 views
1

У меня есть класс, который имеет:преобразования типа указателя в назначении

private: 
    uint32_t *data; 

и тому в одной из функций, которые я делаю:

void foo() { 
    data = new uint32_t[size]; 
} 

и работает нормально. Теперь я хотел бы сделать его немного более гибким, так что я хотел сделать Foo() шаблон:

template<typename T> 
T foo() { 
    data = new T[size]; 
} 

и я пытаюсь использовать его:

class.foo<uint64_t>(); 

Но компиляция не может сказать, что:

error: cannot convert 'long long unsigned int*' to 'unsigned int*' in assignment 

Возможно ли это сделать? Я попытался объявить

void *data; 

и компилируется, но я не могу сделать

sizeof(data[1]); 

, который, по существу, поэтому мне нужно передать тип.

EDIT:

Спасибо за ваши ответы, есть несколько вещь, которую я хотел бы добавить, посмотрев на ваши ответы.

  • Я использую необработанный указатель вместо контейнера, потому что он работает с памятью, которая также используется внешним оборудованием (я не запускаю это на ПК).
  • Использование этой памяти необязательно для этого класса, поэтому я не хочу выделять ее, если она не нужна.
  • Я использую этот класс в нескольких местах, где мне вообще не нужны * данные, поэтому я бы предпочел не сделать весь класс шаблоном.

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

Class<> my; 

но еще:

Class my; 

и при необходимости:

Class<type> my; 

?

+1

насчет T * данные? – snr

+0

Вам нужно преобразовать указатель-член в 'T *' – midor

ответ

1

Вы можете рассмотреть возможность сделать весь ваш класс шаблон, например:

template <typename T> 
class Foo 
{ 
private: 
    T *data; 
public: 
    Foo(size_t size_): 
     data{new T[size]} 
    { 
    } 
    ~Foo() 
    { 
     delete[] data; 
    } 
}; 

Реализация здесь лишь частично. См. Это о rule of 3, 5, 0.

Или с помощью управляемых указателей:

template <typename T> 
class Foo 
{ 
private: 
    std::unique_ptr<T[]> data; 
    size_t size; 
public: 
    Foo(size_t size_): 
     data{std::make_unique<T[]>(size_)}, 
     size(size_) 
    { 
    } 
    ~Foo() 
    { 
     // no need to call delete, unique_ptr will do it 
    } 
}; 

Но как только вы здесь, в зависимости от вашего случая использования альтернативы может быть предпочтительнее, как std::vector:

std::vector<uint64_t> v(size); 
// ... 
std::cout << v.size() << std::endl; 

EDIT:

Из дополнительной информации, которую вы предоставили, выглядит следующим образом: ДШ:

class Base 
{ 
public: 
    virtual void* get_data() { 
     return nullptr; 
    } 
    virtual size_t get_size() { 
     return 0; 
    } 
}; 

template<typename T> 
class Foo : public Base 
{ 
private: 
    T* data; 
    size_t size; 
public: 
    Foo(size_t size_): 
     data{new T[size_]}, 
     size(size_) {} 
    ~Foo() { 
     delete[] this->data; // same remark as above about rule of 5 
    } 
    virtual void* get_data() overriden { 
     return this->data; 
    } 
    virtual size_t get_size() overriden { 
     return this->size; 
    } 
}; 

Со следующим использованием:

std::unique_ptr<Base> my_without_data = 
    std::make_unique<Base>(); 

std::unique_ptr<Base> my_with_data = 
    std::make_unique<Foo<type>>(size); 

Обратите внимание, что во втором вызове, std::make_unique возвращает unique_ptr<Foo<type>> с соответствующим Deleter вызывающего Foo<type> «s деструктор. Делектор будет скопирован при назначении my_with_data и вызовет деструктор Foo<type>, даже если деструктор Base не объявлен виртуальным.

Я выбрал здесь дизайн с виртуальными методами в Base для доступа к data. В зависимости от вашего реального варианта использования могут использоваться другие способы.

+0

Я отмечу, что вы отвечаете как решение, но на самом деле значение шаблона по умолчанию - это, я думаю, лучшее, что я могу сделать, хотя я искал что-то еще. – corwin

+0

@corwin Я отредактировал свой ответ другим предложением. Скажите, если он более приспособлен к вашему делу. – wasthishelpful

+0

Хорошо, это довольно интересно, я думаю, что это может сработать, спасибо. – corwin

2

Вместо преобразования вашей функции в шаблон, преобразовать класс в шаблон:

template <class T> 
class myclass { 
private: 
    T *data; 
public: 
    myclass(size_t size) : data(new T[size]) { 
    } 
    ... // Add copy constructor, assignment operator, and a destructor 
     // to properly manage the pointer. See "rule of three" for more info. 
}; 

Таким образом тип элемента массива становится частью типа вашего класса, позволяя ваши функции-члены работать с data без дополнительного литья.

Обратите внимание, что использование указателя raw-массива в классе сопряжено со значительными обязательствами с точки зрения управления памятью.Вам будет лучше с std::vector<T>.

+0

Спасибо, но я бы предпочел избежать этого. Потому что использование «данных» является вариантом для этого класса, поэтому я не хочу выделять память для него, если я его не буду использовать. Мне нужно создать класс с некоторым типом по умолчанию для «данных» и изменить его позже. – corwin

1

Преобразовать весь свой класс шаблонного класса

template<typename T> 
class Container { 
public: 
    Container() : 
     data(NULL) 
    {} 
    ~Container() { 
     if (data) { 
      delete [] data; 
     } 
    } 
    T* foo(int size) { 
     if (data) { 
      delete [] data; 
     } 
     data = new T[size]; 
     return data; 
    } 
private: 
    T *data; 
}; 
Смежные вопросы