Почему вы используете указатели в определении класса?

У меня довольно слабое понимание указателей с самого начала, но мне немного не повезло, выяснив, зачем они нужны в определениях классов.

Я знаю, что указатели являются типом переменной, которая указывает на адрес памяти другой переменной. Вот где мое настоящее понимание начинается и заканчивается.

Тем не менее, я не могу видеть их использование в начале этого производного класса:

class Circle : public Shape {

private: int* radius;

....
....

}

Почему радиус будет указателем? Какой цели это служит?

0

Решение

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

Три основные цели:

  • Само сообщение (см. Пример ниже)
  • Экономия: если вашей функции нужны 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 методы

3

Другие решения

Указатели позволяют вам воспользоваться множеством изящных языковых функций, полиморфизм и динамическое распределение памяти являются самыми важными в моей голове. Некоторые другие методы, такие как pImpl Идиома также использовать указатели.

В приведенном выше примере объявление radius так как указатель кажется нелогичным (действительно, можно утверждать, что в этом нет необходимости: он не дает никаких реальных преимуществ и все же усложняет вещи для программиста).

Однако есть случаи, когда указатели как члены очень полезны. Рассмотрим следующий случай, когда класс, представляющий Person:

class Person
{
char* _name;
public:
Person(const char* name);
};

Теперь, объявив член name так как указатель позволяет вам выделять память позже, поэтому вы можете выделить только столько памяти, сколько необходимо через ctor, Вы можете использовать массивы, чтобы сделать то же самое, но в итоге вы тратите впустую память.

Как примечание, код для Person Класс определенно не является подходящим способом C ++. Используя std::string был бы способ пойти.

1

Обычно вы используете указатель для ссылки на ресурс, который не принадлежит 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;
}
0