Что лучше неявное преобразование через конструктор или явную функцию в этом случае? - PullRequest
0 голосов
/ 20 сентября 2018

Я создаю свой собственный класс для String, использующий C ++ исключительно для учебных целей.

И я застрял на месте, где я должен принять решение.Позвольте мне объяснить этот вопрос.

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

Опция 1

class String {
    size_t _length;
    char* _stringHead;
public:
    String(const std::string&);
    String(const char*);
    String(const char);
};
String operator+(String, const String);

const bool operator==(const String, const String);
const bool operator!=(const String, const String);
const bool operator<(const String, const String);
const bool operator<=(const String, const String);
const bool operator>(const String, const String);
const bool operator>=(const String, const String);

Опция 2

class String {
    size_t _length;
    char* _stringHead;
public:
    //irrelevant part of code in Option 2
    String(const std::string&);
    String(const char*);
    String(const char);
    //irrelevant part of code in Option 2
};
String operator+(String, const String&);

const bool operator==(const String&, const String&);
const bool operator!=(const String&, const String&);
const bool operator<(const String&, const String&);
const bool operator<=(const String&, const String&);
const bool operator>(const String&, const String&);
const bool operator>=(const String&, const String&);

//for std::string
String operator+(String, const std::string&);

const bool operator==(const String&, const std::string&);
const bool operator!=(const String&, const std::string&);
const bool operator<(const String&, const std::string&);
const bool operator<=(const String&, const std::string&);
const bool operator>(const String&, const std::string&);
const bool operator>=(const String&, const std::string&);

String operator+(const std::string&, String);

const bool operator==(const std::string&, const String&);
const bool operator!=(const std::string&, const String&);
const bool operator<(const std::string&, const String&);
const bool operator<=(const std::string&, const String&);
const bool operator>(const std::string&, const String&);
const bool operator>=(const std::string&, const String&);
//for std::string

//the same goes for char* and char
...
//the same goes for char* and char

Итак, как вы можете видеть из Вариант 1 и Вариант 2 указывает, что решение здесь заключается в том, использовать ли неявное преобразование типов, которое выполняется с помощью конструкторов, или вводить каждую утилиту отдельно для каждого типа, с которым я хочу свой String type to work.

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

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

1 Ответ

0 голосов
/ 20 сентября 2018

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

Например, запустите этот код, который похож на ваш:

#include <iostream>

class String {
 public:
  String(const std::string& s) {
    std::cout << "called" << std::endl;
  };
};

std::ostream& operator<< (std::ostream& stream, const String& s) {
  return stream;
}

void hello(String s) {
  std::cout << "Hello " << s; // Outputs "called" before "Hello ".
}

int main() {
  std::string s = "world";
  hello(s); // Uses the implicit conversion constructor.
}

Поскольку новый экземпляр класса Stringнеобходимо создавать каждый раз, следует ожидать, что производительность будет слегка снижаться .Но, на мой взгляд, этого недостаточно, чтобы перевесить преимущества: неявное преобразование может значительно упростить работу дизайнера классов и упростить использование класса.

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

Вот такой пример:

#include <iostream>

class String {
 public:
  String(int size) {};
};

std::ostream& operator<< (std::ostream& stream, const String& s) {
    return stream;
}

void hello(String s) {
  std::cout << "Hello " << s; // Prints "Hello " as no error occurs.
}

int main() {
  hello(10); // It still calls the implicit conversion constructor.
}

В приведенном выше коде сообщение об ошибкесозданный ключевым словом explicit может сэкономить кому-то немного времени, потраченного на отладку.

Некоторые обстоятельства, при которых неявное преобразование имеет смысл:

  1. Класс достаточно дешев, чтобы построитьвас не волнует, неявно ли он создан.
  2. Некоторые классы концептуально похожи на свои аргументы , например std::string, отражающие ту же концепцию, что и const char*, которую он может неявно преобразовать из, поэтому неявное преобразование имеет смысл, как и здесь.
  3. Некоторые классы становятся намного болееПриятно использовать, если неявное преобразование отключено. Подумайте о необходимости явно создавать std::string каждый раз, когда вы хотите передать строковый литерал.

Некоторые обстоятельства, в которых неявное преобразование имеет меньше смыслаявляются:

  1. Строительство стоит дорого.
  2. Классы концептуально очень отличаются от своих аргументов. Рассмотрим пример с String и int.
  3. Конструкция может иметь нежелательные побочные эффекты. Например, класс AnsiString не должен неявно конструироваться из UnicodeString, поскольку преобразование Unicode-в-ANSI может потерять информацию.

Итак, мой совет в вашем конкретном случае - использовать преобразование, потому что оно имеет смысл, поскольку ваш класс очень похож на std::string и минимизирует дублирование кода, но в будущем использовать неявное преобразование с мыслью .

...