У меня довольно слабое понимание указателей с самого начала, но мне немного не повезло, выяснив, зачем они нужны в определениях классов.
Я знаю, что указатели являются типом переменной, которая указывает на адрес памяти другой переменной. Вот где мое настоящее понимание начинается и заканчивается.
Тем не менее, я не могу видеть их использование в начале этого производного класса:
class Circle : public Shape {
private: int* radius;
....
....
}
Почему радиус будет указателем? Какой цели это служит?
Варианты использования указателей основаны на том факте, что два объекта, указатели которых ссылаются на одну и ту же область памяти, могут обмениваться данными через эту память.
Три основные цели:
BigFatObject
в качестве параметра, то вы объявляете этот параметр, чтобы иметь тип BigFatObject*
, Таким образом, вы уменьшаете использование стека от sizeof(BigFatObject)
(который может быть огромным) для sizeof(void*)
(что обычно составляет всего 4/8 байтов)Например:
class SharedObject
{
public:
int getValue() { return value; }
void setValue(int value) { this->value = value; }
private:
int value;
};
class CommunicatesThroughSharedObject
{
public:
CommunicatesThroughSharedObject(SharedObject *shared)
{
this->shared = shared;
}
private:
SharedObject *shared;
};
SharedObject shared;
CommunicatesThroughSharedObject c1(&shared), c2(&shared);
Теперь вы можете получить c1
а также c2
общение через вызов их shared
переменной getValue
а также setValue
методы
Указатели позволяют вам воспользоваться множеством изящных языковых функций, полиморфизм и динамическое распределение памяти являются самыми важными в моей голове. Некоторые другие методы, такие как pImpl
Идиома также использовать указатели.
В приведенном выше примере объявление radius
так как указатель кажется нелогичным (действительно, можно утверждать, что в этом нет необходимости: он не дает никаких реальных преимуществ и все же усложняет вещи для программиста).
Однако есть случаи, когда указатели как члены очень полезны. Рассмотрим следующий случай, когда класс, представляющий Person:
class Person
{
char* _name;
public:
Person(const char* name);
};
Теперь, объявив член name
так как указатель позволяет вам выделять память позже, поэтому вы можете выделить только столько памяти, сколько необходимо через ctor
, Вы можете использовать массивы, чтобы сделать то же самое, но в итоге вы тратите впустую память.
Как примечание, код для Person
Класс определенно не является подходящим способом C ++. Используя std::string
был бы способ пойти.
Обычно вы используете указатель для ссылки на ресурс, который не принадлежит Class, возможно, он используется совместно с другими кругами. Указатели также могут быть полезны для полиморфизма. Указатель может указывать на базовый класс, а фактический тип не определяется до времени выполнения. Все это может быть достигнуто с большей безопасностью, используя ссылки, но преимущество указателей в том, что они могут быть обнуляемыми, поэтому их можно использовать, если ресурс может не существовать в момент создания круга.
Это не имеет большого смысла для радиуса, но может быть для регистратора:
#include <iostream>
#include <string>
class Logger {
public:
virtual ~Logger() {}
virtual void log(const std::string& message) = 0;
};
class FileLogger : public Logger {
public:
void log(const std::string& message) {/*...*/ }
};
class TestLogger : public Logger {
public:
void log(const std::string& message) { std::cout << message << std::endl;}
};
class Shape {
//...
};
class Circle : public Shape {
private:
int radius;
Logger* logger;
//...
public:
Circle() : radius(1), logger(nullptr) {}
void setLogger(Logger* in) {logger = in;}
void doSomething() {
//...
if (logger != nullptr)
logger->log("Did something");
}
};
int main() {
Circle circle;
circle.doSomething();
TestLogger logger;
circle.setLogger(&logger);
circle.doSomething();
return 0;
}