#c #templates #casting #operator-overloading #private-members
#c #шаблоны #Кастинг #оператор-перегрузка #private-members
Вопрос:
Я пытаюсь реализовать перегруженный оператор приведения в моем шаблонном array2d
классе, используя type T
. Итак, я должен выполнить приведение из array2d<T>
в новый array2d<E>
.
Я могу выполнить приведение сам, но проблемы возникают, когда я пытаюсь установить приведенные данные в новый экземпляр array2d<E>
. Компилятор сообщает мне, что оператор приведения не имеет доступа к закрытым элементам array2d
Вот где я нахожусь до сих пор (отредактировал несвязанный код для краткости)
array2d.h
template<typename T>
class array2d {
private:
// Member Variables
T** data;
size_t width, height;
public:
// constructors, methods, etc...
// Cast Operator
template<typename E>
operator array2d<E>() const;
};
// Other overloaded operators...
// Overloaded Casting Operator
template<typename T>
template<typename E>
array2d<T>::operator array2d<E>() const{
// Create new instance
array2d<E> castedArr(width, height);
// Allocate memory for the casted data, then cast each element
E** newData = new E*[castedArr.get_height()];
for (size_t i = 0; i < castedArr.get_height(); i ){
newData[i] = new E[castedArr.get_width()];
for (size_t j = 0; j < castedArr.get_width(); j ){
newData[i][j] = (E)data[i][j];
}
}
// issue here, can't set data because it's private.
castedArr.data = newData;
delete [] newData;
newData = nullptr;
return castedArr;
}
main.cpp
#include "array2d.h"
int main(int argc, char *argv[]) {
// Cast Operator
// Create an array2d<T> of
// width = 5
// height = 5
// fill all elements with 42.1
array2d<double> x(5, 5, 42.1);
// Create a new array exactly the same as
// x, where x is casted to int
array2d<int> y = (array2d<int>) x;
return 0;
}
Это меня смутило, поскольку у меня есть много других перегруженных операторов, которые могут получить доступ к закрытым элементам, используя практически ту же логику.
Почему это происходит и что я могу сделать, чтобы исправить это?
Комментарии:
1. Не связано: вы не хотите
delete[] newData
. Вы назначили эти данные вcastedArr
, который является новым владельцем и отвечает за удаление указателя, когда это будет сделано с ним.2. Как я уже сказал @lubgr , если не использовать
delete [] newData
, деструктор нового экземпляра удостоверится, что он удален?3. Это не решает вопрос, но этот вопрос касается оператора преобразования , а не оператора приведения . Приведение — это то, что вы пишете в своем исходном коде, чтобы сообщить компилятору выполнить преобразование. Многие преобразования могут быть выполнены без приведения.
Ответ №1:
При написании шаблона вы не указываете фактический тип, вы создаете предварительный вариант для разных типов. array2d<double>
и array2d<int>
— это разные типы, и по умолчанию два экземпляра двух разных классов не могут получить доступ к своим закрытым элементам.
Это можно исправить, объявляя каждый экземпляр array2d
дружественного класса шаблона array2d
:
template<typename T>
class array2d {
/* ... */
template<class E> friend class array2d;
/* ... */
};
В качестве примечания, я не совсем уверен, что
delete [] newData;
это хорошая идея. Вы уничтожаете части ресурсов, которыми должен управлять новый array2d
экземпляр. Если вы delete[]
это повторите array2d::~array2d()
, у вас будет неопределенное поведение.
Комментарии:
1. Большое спасибо, это было решение! Примечание к несвязанной стороне: если я этого не сделаю
delete [] newData
, позаботится ли об этом деструктор для этого экземпляра?2. Вам определенно нужно реализовать деструктор самостоятельно. И вам нужно вручную
delete[]
как «внутреннее» хранилище для каждой строки, так и «внешнее». Просто идентичные вызовыnew[]
.