Определение статического экземпляра класса

#c

#c

Вопрос:

Я определил Vector2 класс и подумал, что было бы неплохо иметь некоторые предопределенные элементы, такие как нулевой вектор или вектор, указывающий вправо.

Я создал следующий метод для нулевого вектора:

 static inline Vector2 ZERO() {return Vector2(0, 0);}
  

Можно ли сделать это таким образом, или есть какие-то более разумные / эффективные способы сделать это, например, инициализировать нулевой вектор как const и указывать только на него?

Комментарии:

1. Вы должны обязательно объявить ZERO как const (какой смысл его менять?). В остальном все выглядит нормально.

2. Если они действительно дешевы в создании, вам может просто понадобиться zero() фабричный метод или конструктор по умолчанию, который равен нулю.

3. Являются ли эти векторы изменяемыми или неизменяемыми?

Ответ №1:

Я думаю, что это хороший способ. Но конструктор vector2 определен, нет необходимости использовать статическую функцию. Vector2 vZero = Vector2::ZERO(); // сложный, Vector2 vZero(0,0); // более простой.

Если вы хотите более легко,

 Vector2{ 
public: 
    static const Vector2 ZEROVECTOR = Vector2(0,0);
...}
  

Вы можете использовать if(vVector == Vector2::ZEROVECTOR) ;// только один пустой вектор для каждого класса vector2 .

Ответ №2:

Еще одна идея:

Вы можете определить enum для специального инициализатора, чтобы охватить некоторые из распространенных экземпляров.

Для этого не требуются сохраненные константы и только один дополнительный конструктор.

Пример:

 #include <iostream>

// initializers for common things
enum Init {
  Init0, // init a 0-vector
  InitX, // init an x unit vector
  InitY // init a y unit vector
};

struct Vector2 {
  double x, y;
  
  Vector2(Init init = Init0):
    x(init == InitX), y(init == InitY)
  { }
  
  Vector2(double x, double y): x(x), y(y) { }
};

std::ostreamamp; operator<<(std::ostream amp;out, const Vector2 amp;v)
{
  return out << v.x << ", " << v.y;
}

#define DEBUG(...) std::cout << #__VA_ARGS__ << ";n"; __VA_ARGS__ 

int main()
{
  DEBUG(Vector2 v0);
  DEBUG(std::cout << v0 << 'n');
  DEBUG(Vector2 v1(Init0));
  DEBUG(std::cout << v1 << 'n');
  DEBUG(Vector2 v2(InitX));
  DEBUG(std::cout << v2 << 'n');
  DEBUG(Vector2 v3(InitY));
  DEBUG(std::cout << v3 << 'n');
  DEBUG(Vector2 v4(1.0, 2.0));
  DEBUG(std::cout << v4 << 'n');
}
  

Вывод:

 Vector2 v0;
std::cout << v0 << 'n';
0, 0
Vector2 v1(Init0);
std::cout << v1 << 'n';
0, 0
Vector2 v2(InitX);
std::cout << v2 << 'n';
1, 0
Vector2 v3(InitY);
std::cout << v3 << 'n';
0, 1
Vector2 v4(1.0, 2.0);
std::cout << v4 << 'n';
1, 2
  

Живая демонстрация на coliru

Пожалуйста, обратите внимание, что я этого Vector2::Vector2(Init) не explicit сделал.

Обычно я предпочитаю создавать конструкторы только с одним аргументом explicit , чтобы предотвратить случайные преобразования (там, где я их не ожидаю). В этом случае я бы предпочел, чтобы InitX его можно было использовать непосредственно там, где Vector2 ожидается (запуск неявного преобразования). Это делает эту функцию еще более удобной. (Я должен признать, что я назвал его, например XAxis , вместо InitX того, чтобы в моем реальном коде.)