C ++ ma funkcję (nie potrafię ustalić jej właściwej nazwy), która automatycznie wywołuje pasujące konstruktory typów parametrów, jeśli typy argumentów nie są oczekiwanymi.
To bardzo prosty przykład jest to wywołanie funkcji, która spodziewa się std::string
z const char*
argumentem. Kompilator automatycznie wygeneruje kod w celu wywołania odpowiedniego std::string
konstruktora.
Zastanawiam się, czy to jest tak złe dla czytelności, jak mi się wydaje?
Oto przykład:
class Texture {
public:
Texture(const std::string& imageFile);
};
class Renderer {
public:
void Draw(const Texture& texture);
};
Renderer renderer;
std::string path = "foo.png";
renderer.Draw(path);
Czy to w porządku? Czy to idzie za daleko? Jeśli nie powinienem tego zrobić, czy mogę w jakiś sposób zmusić Clanga lub GCC do ostrzeżenia?
Odpowiedzi:
Nazywa się to konstruktorem konwertującym (lub czasem niejawnym konstruktorem lub niejawną konwersją).
Nie znam przełącznika czasu kompilacji, który ostrzega, kiedy to nastąpi, ale bardzo łatwo jest temu zapobiec; wystarczy użyć
explicit
słowa kluczowego.To, czy konwersja konstruktorów jest dobrym pomysłem: zależy.
Okoliczności, w których domniemana konwersja ma sens:
std::string
odzwierciedlenie tego samego pojęcia, zconst char *
którego można niejawnie przekonwertować), więc konwersja niejawna ma sens.Okoliczności, w których domniemana konwersja ma mniej sensu:
AnsiString
klasa nie powinna niejawnie konstruować z aUnicodeString
, ponieważ konwersja Unicode na ANSI może spowodować utratę informacji.Dalsza lektura:
źródło
To jest bardziej komentarz niż odpowiedź, ale zbyt duży, aby można go było wstawić.
Co ciekawe,
g++
nie pozwala mi tego zrobić:Wytwarza następujące:
Jeśli jednak zmienię wiersz na:
Dokonuje tej konwersji.
źródło
gcc
opcje kompilatora (które nie wyglądają na takie, które mogłyby rozwiązać ten konkretny przypadek). Nie zagłębiałem się w to (powinienem pracować :-), ale biorąc pod uwagęgcc
przestrzeganie standardu i użycieexplicit
słowa kluczowego opcja kompilatora prawdopodobnie została uznana za niepotrzebną.Texture
prawdopodobnie nie należy ich budować w sposób dorozumiany (zgodnie z wytycznymi w innych odpowiedziach), więc byłaby lepsza strona wywołującarenderer.Draw(Texture("foo.png"));
(zakładając, że działa zgodnie z oczekiwaniami).Nazywa się to konwersją typu niejawnego. Ogólnie rzecz biorąc, jest to dobra rzecz, ponieważ hamuje niepotrzebne powtarzanie. Na przykład automatycznie otrzymujesz
std::string
wersjęDraw
bez konieczności pisania dla niej dodatkowego kodu. Może również pomóc w przestrzeganiu zasady otwartego zamknięcia, ponieważ pozwala rozszerzyćRenderer
możliwości bez modyfikacjiRenderer
.Z drugiej strony nie jest to pozbawione wad. Może z jednej strony utrudnić ustalenie, skąd pochodzi argument. Czasami może przynieść nieoczekiwane wyniki w innych przypadkach. Po to
explicit
jest słowo kluczowe. Jeśli umieścisz go wTexture
konstruktorze, spowoduje to wyłączenie tego konstruktora do niejawnej konwersji typu. Nie znam metody globalnego ostrzegania przed niejawną konwersją typów, ale to nie znaczy, że metoda nie istnieje, tylko że gcc ma niezrozumiale dużą liczbę opcji.źródło