Неоднозначный вызов оператора [] внутри вложенного класса
Я пытаюсь создать структуру данных, которая имеет векторные функции для изучения C++. В настоящее время я застрял, пытаясь скомпилировать код, подобный этому:
template<typename T>
class TestClass {
public:
T* data;
TestClass(const T& t) {
data = new T{ t };
}
~TestClass(void) {}
TestClass(const TestClass&) {}
T& operator[](int k) { return *data; }
const T& operator[](int k) const { return *data; }
class NestedClass {
public:
NestedClass(void) {}
~NestedClass(void) {}
T& operator*(void) { return operator[](0); }
};
NestedClass newNestedClass(void) {
return new NestedClass();
}
};
Я получаю неоднозначный вызов перегруженной функции на моем operator*
функция внутри моего вложенного класса. Хотя я думаю, что я получаю проблему (как компилятор узнает, если это его rhs/lhs), я не совсем уверен, как это исправить. Я хочу использовать operator[]
Функция для этого.
Я ожидаю, что эти две строки будут печатать одно и то же:
TestClass<int> t(1);
auto n = t.newNestedClass();
cout << t[0] << endl;
cout << *n << endl;
return 0;
Любой совет?
1 ответ
operator[]
что вы определили для вашего TestClass
никоим образом не "унаследован" или как-то "встроен" в ваш вложенный класс.
Вы можете думать о вложенных классах C++ как об обычных классах, которые живут в "вложенном пространстве имен": TestClass::NestedClass
в вашем примере кода.
Если вы хотите operator[]
для вашего вложенного класса, вы должны определить один с нуля (как вы сделали для вашего TestClass
).
РЕДАКТИРОВАТЬ 1: Возвращая классы (C++ не Java)
Также обратите внимание, что C++ не похож, например, на Java (с шаблоном распределения экземпляров классов с new
и полагаться на сборщик мусора для автоматического сбора "мусора").
Итак, код такой:
NestedClass newNestedClass(void) { return new NestedClass(); }
не должен даже компилироваться.
Если вы вернули NestedClass
Экземпляр динамически распределяется с new
, вы должны вернуть указатель на него, например:
// Note the "*" for the returned pointer
NestedClass* newNestedClass() {
return new NestedClass();
}
Но это скорее шаблон Java.
В C++ вы можете просто захотеть вернуть экземпляр NestedClass без new
динамическое распределение; это должно работать просто отлично:
NestedClass newNestedClass() {
return NestedClass();
}
РЕДАКТИРОВАТЬ 2: Правильное управление ресурсами
Обратите внимание, что вы можете сделать T* data;
член private
для лучшей инкапсуляции и сокрытия информации. Вы предоставляете надлежащие общедоступные средства доступа (например, operator[]
перегрузки) для доступа к данным вашего класса: предоставьте доступ к функциям-членам средства доступа, а не к членам-данным.
Более того, вы динамически выделяетесь data
в кучу, используя new
, Вы должны освободить динамически выделенную кучу памяти, чтобы избежать утечек памяти (и ресурсов).
Хорошее место для этого - деструктор вашего класса, например:
class TestClass {
private:
T* data;
public:
...
~TestClass() {
// Release resoruces dynamically allocated
delete data;
}
}
Обратите внимание, что этот код:
data = new T{t};
просто динамически выделяет один экземпляр T
, инициализируя его значением t
,
Соответствующий код очистки:
delete data;
Однако, если вы хотите динамически выделить массив T
s, синтаксис:
data = new T[elementCount];
// ... initialize data to some value...
и соответствующий синтаксис очистки:
delete[] data; // Note the []!!
Также обратите внимание, что если вы хотите вручную управлять ресурсами в своем классе, вы должны рассмотреть также определение конструктора копирования и назначения копирования operator=()
(см. так называемое правило трех); и если вы хотите реализовать семантику перемещения, вам также следует рассмотреть возможность реализации конструктора перемещения и назначения перемещения (в этом случае есть соответствующее "Правило 5").
Но если вы полагаетесь на уже имеющихся менеджеров ресурсов RAII, как std::vector
вам не нужно тратить время, энергию и на поиск ошибок, управляя ресурсами вручную: все это автоматически управляется std::vector
или любой другой контейнерный класс, который вы выберете (в этом случае у вас есть простое "Правило нуля":), то есть конструктор копирования, сгенерированный компилятором по умолчанию, оператор присваивания копии, конструктор перемещения, оператор присваивания перемещения и деструктор сделают трудную задачу.
Но, конечно, если это учебное упражнение, вы можете реализовать эти специальные функции-члены самостоятельно.