Самый короткий и простой ответ будет ДА!

Второй вопрос: КАК?

Поймите заявление

Утверждение, которое мы пытаемся оценить, выглядит примерно так:

x ** y;

Какие должны быть виды?

Одно можно сказать наверняка; нам нужно перегрузить некоторые операторы. Чтобы перегрузить оператор в C++, он должен принимать как минимум один определяемый пользователем объект в качестве аргумента. При этом либо x, либо y должны быть объектом класса/структура.

Я покажу вам позже, но сейчас, поверьте мне, будет лучше, если этот объект будет вторым аргументом, который в данном случае равен y. Тип x может быть любым примитивным типом, но я предпочитаю double.

Как должен выглядеть этот класс?

класс будет внутренне сохранять double (или любой другой примитивный тип, но лучше использовать double). Давайте посмотрим на этот класс.

class Exponent {
public:
  Exponent(double y) : y{y} {}

private:
  double y;
};

Используя это определение, теперь мы можем создать объект класса Exponent класса и обращаться с ним как с двойником. Давайте теперь создадим объект этого класса.

Как использовать этот класс?

Вот как мы можем создать объект этого класса в main() (или где-либо еще, если на то пошло).

class Exponent {
public:
  Exponent(double y) : y{y} {}

private:
  double y;
};

int main() {
  double x{2.};
  Exponent y{4.};

  auto result{x ** y}; // Won't work yet (of course)

}

Давайте сломаем это

Если присмотреться 🧐, то легко понять, что нам здесь нужно сделать. Я покажу вам, как…

Третья строка в функции main(), где мы вызываем оператор, присмотритесь! Мы также можем написать это как,

auto result{x * *y};

Поскольку C++ не чувствителен к отступам и пробелам, этот код точно такой же, как и выше. К настоящему моменту вам уже должно быть кристально ясно, что мы должны сделать, чтобы это заработало.

Подготовка вещей

Первое, что нам нужно сделать, это перегрузить косвенный оператор Exponent. > класс. Но что бы он сделал🤔? Ну, мы только хотим, чтобы компилятор был доволен тем, что наш класс имеет оператор в этом роде. Нам нужно только отправить объект фактическому оператору (это мы скоро увидим). Давайте посмотрим код. Это будет иметь больше смысла 😁.

class Exponent {
public:
  Exponent(double y) : y{y} {}

  Exponent& operator*() {
    return *this;
  }

private:
  double y;
};

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

const Exponent& operator*() const {
    return *this;
  }

Теперь давайте посмотрим, как мы можем реализовать оператор, который принимает двойник и экспонент. strong> и вызывает для них метод std::pow.

// Prototype of the operator
double operator*(double x, Exponent y);

// This should also be made friend of the
// Exponent class because we need to
// access its member 'y'.
class Exponent {
public:
  Exponent(double y) : y{y} {}

  Exponent& operator*() {
    return *this;
  }

private:
  // doesn't have to be private though
  friend double operator*(double x, Exponent y);
  double y;
};

Реализация оператора

Давайте теперь посмотрим весь код с полной реализацией.

#include <iostream>
#include <cmath>

class Exponent {
public:
  Exponent(double y) : y{y} {}

  Exponent& operator*() { return *this; }
  const Exponent& operator*() const { return *this; }

private:
  friend double operator*(double x, Exponent y);
  double y;
};

double operator*(double x, Exponent y) {
  return std::pow(x, y.y);
}

int main() {
  double x{2.};
  Exponent y{4.};

  auto result{x ** y};

  std::cout << "result = " << result << std::endl;

}

Это все, что вам нужно для этого. Он выведет ожидаемый результат.

Что, если мы переставим переменные?

Что, если мы хотим написать код таким образом, чтобы объект Exponent (определяемый пользователем) был первым аргументом, а двойной? em> переменная вторая?

auto result{y ** x}; // What about this one??

Чтобы это сработало, у вас будет несколько способов. Проще всего использовать (двойной) указатель.

int main() {
  double number{2.};
  auto x{&number}; // double*
  Exponent y{4.};

  auto result{y ** x};
}

Теперь, поскольку первый аргумент является определяемым пользователем объектом, мы можем перегрузить член оператора нашего класс. Посмотрим, как…

class Exponent {
public:
  Exponent(double y) : y{y} {}

  double operator*(double y) { return std::pow(this->y, y); }

private:
  friend double operator*(double x, Exponent y);
  double y;
};

Не путайтесь в именах переменных! x обрабатывается как y в операторе, поэтому я назвал его здесь y. Не стесняйтесь переименовывать его в то, что имеет для вас смысл.

Компиляция этого кода сейчас даст нам ожидаемый результат. Давайте посмотрим весь код в одном месте.

#include <iostream>
#include <cmath>

// be better if we renamed it to Base now 😅
class Exponent {
public:
  Exponent(double y) : y{y} {}

  double operator*(double y) { return std::pow(this->y, y); }

private:
  friend double operator*(double x, Exponent y);
  double y;
};

int main() {
  double number{2.};
  auto x{&number};
  Exponent y{4.};

  auto result{y ** x};

  std::cout << "result = " << result << std::endl;
}

Другие способы сделать то же самое

Я бы не советовал делать это 🥴, но с современными функциями C++ (C++11 и выше), мы можем сделать что-то действительно классное.

int main() {
  double x{2.};
  Exponent y{4.};

  auto result{y ** ((double*)&x)};

  std::cout << "result = " << result << std::endl;
}

При этом адрес этой переменной преобразуется в двойной указатель только для последующего разыменования. Это будет работать так же.

А где же современные черты, спросите вы…

Ну есть еще…

int main() {
  double x{2.};
  Exponent y{4.};

  auto result{y ** (&(double&)std::move(2.))};

  std::cout << "result = " << result << std::endl;
}

Это также даст вам тот же результат.

Заключение

Вы могли заметить, что я использовал ссылку в некоторых местах и ​​копию в других. Вы можете использовать ссылку везде (для этого конкретного случая), поскольку класс Exponent хранит только двойник внутренне, что составляет 8 байт. Ссылка — это просто адрес, который в 64-битной архитектуре также занимает 8 байт (отсюда и 64-битная 😉). В любом случае это не будет иметь большого значения. Хотя вы можете обмениваться ссылками и копиями, если хотите.

Я также преподаю программирование на YouTube 🙃. Если вам нравится, как я объясняю вещи, загляните и на мой канал. Возможно, вам это даже больше понравится 😄.

CodeMite (хинди)

eN. Программирование (английский)

Инстаграм

И если вы понимаете хинди, я также снял видео на эту тему, посмотрите здесь.