2016-06-23 25 views
8

Mit Clang 3.7 auf Windows-PlattformFehler: Basisklasse 'A1' hat ein eigenes Copykonstruktor

folgenden Code anzeigen:

class A1 
{ 
public: 
    A1(char* name){} 
    virtual ~A1() {} 
private: 
    A1(const A1&) {} 
}; 

class B1 : public A1 
{ 
public: 
    B1(): A1(""){} 
}; 

ich die folgende Fehlermeldung erhalten:

MyFile(31): 8: error: base class 'A1' has private copy constructor 
     B1(): A1(""){} 
      ^
MyFile(25): 2: note: declared private here 
     A1(const A1&) {} 
     ^

A1 machen Kopiere Konstruktor öffentlich, beseitigt den Fehler!

Was ist hier passiert?

Hinweis: dass das Ändern von (wie ich sollte)

A1(const char* name) 

ich keine Fehlermeldungen erhalten und alle kompilieren als

erwartet
+5

@Andrew Ich denke, die Frage ist, warum ist der Kopierkonstruktor überhaupt erforderlich. – juanchopanza

+4

Es gibt keine Zeile '31' in Ihrem Code. Bitte poste ein [MCVE] (http://stackoverflow.com/help/mcve) –

+0

'A1 (" ")' ist ein Fehler, weil 'A1' keinen Konstruktor hat, der ein Zeichenfolgenliteral akzeptiert; Der Fehler, den Sie veröffentlichen, ist wahrscheinlich eine Kaskade von diesem Fehler (und sollte daher ignoriert werden, da er verschwindet, sobald Sie den ursprünglichen Fehler behoben haben) –

Antwort

3

Sie können den Konstruktor A1(char* name) nicht mit einem String-Literal aufrufen, da ein String-Literal nicht in char* konvertiert werden kann (eine solche veraltete Konvertierung existierte vor C++ 11). Oder, ein Programm, das den Konstruktor aufruft, ist schlecht ausgebildet, und die Implementierung darf die Kompilierung ablehnen.

Daher sucht die Überladungsauflösung nach anderen Alternativen. Die einzige andere mögliche Alternative, die die gleiche Anzahl von Argumenten hat, ist der Kopierkonstruktor.

Aus irgendeinem Grund scheint clang die implizite Konvertierung von Zeichenfolgenliteral zu A1 vorzuziehen, wodurch ein temporäres Objekt erstellt wird, das für die Kopierinitialisierung verwendet werden kann, anstatt die direkte Konstruktion aus dem Literal zu verwenden. Dieses Verhalten führt zu dem verwirrenden Kompilierungsfehler.

Beide Alternativen sind schlecht gebildet, und Clang warnt davor: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]. Das Programm kompiliert, wenn Sie den Standardmodus auf älter als C++ 11 setzen (in diesem Fall wäre das Programm wohlgeformt, obwohl es eine veraltete Konvertierung verwendet).Interessanterweise, wenn wir die Umwandlung nicht zulassen, dann stellt das Programm auch in dem aktuellen Standard-Modus:

class A1 
{ 
public: 
    explicit A1(char* name){} // note the explicit 
    virtual ~A1() {} 
private: 
    A1(const A1&) {} 
}; 

G ++ verhält sich anders und Ihr Programm kompiliert fein (mit der entsprechenden Warnung natürlich). Beide Compiler scheinen in dieser Hinsicht dem Standard zu entsprechen.

Moral der Geschichte: Lesen Sie immer auch die Warnungen. In diesem Fall war die Warnung vollkommen klar und einfach zu lösen, während derselbe Fehler indirekt einen Fehler verursachte, der beim Lösen des Fehlers nicht hilfreich war.

+0

Danke! Wenn ich ctor auf public (nur zum Verständnis) setze und den Debugger starte, sehe ich, dass zuerst A1 (char * name) ctor ausgeführt wird und dann ctor kopiert wird. Bei expliziter Verwendung von A1 (char * name) wird nur dieser ctor aufgerufen. –

6

Ich kann mir vorstellen, dass dies nur ein Artefakt, wie die Diagnose generiert.

  • Zuerst Lookup versucht, einen Konstruktor zu finden Ihre „Anruf“ zu passen (es ist kein Anruf ist, aber was auch immer)
  • Der Ctor char* Einnahme nicht übereinstimmt, wie Sie
  • Der einzige andere Kandidaten kennen private ist
  • Der Compiler zu sehen versucht, ob es eine temporäre A1 von Ihrem "" Argument instanziieren kann, um diese Arbeit zu machen
  • dabei wieder alles was man finden kann, ist private Bauer
  • Der Compiler entscheidet, darüber zu klagen, bevor

Ein Macht argumentieren, dass dies eine Qualität des Implementierungsproblems etwas anderes tun.

Amüsant, GCC 6.1.0 (even in pedantic C++14 mode) compiles your code as originally written, spuckte nur eine Warnung für die gebrochene wörtliche Umwandlung aus.