2016-04-12 13 views
2

Beim Verweisen auf Referenzen scheint der Compiler die Derived-Klasse in Base zu konvertieren und verwendet die benutzerdefinierte Umwandlung überhaupt nicht. Dies funktioniert jedoch tadellos mit Zeigern.Benutzerdefinierte Umwandlung wurde nicht auf Referenzen der abgeleiteten Klasse angewendet

Beispiel:

#include <iostream> 

class Base { 
public: 
    int fn() { 
     return 42; 
    } 
}; 

class Derived : private Base { 
public: 
    operator Base&() { 
     return *dynamic_cast<Base*>(this); 
    } 

    operator Base*() { 
     return dynamic_cast<Base*>(this); 
    } 
}; 

int main() { 
    Derived d; 
    Derived &dRef = d; 

    std::cout<<static_cast<Base&>(dRef).fn()<<std::endl; // <-- error: non-reachable base >>Base<<of>>Derived<< 
    std::cout<<static_cast<Base*>(d)->fn()<<std::endl;  // OK -> "42" 
} 

Warum ist es nicht möglich, die individuelle wie diese werfen zu benutzen? Ist es möglich, das beabsichtigte Verhalten zu erreichen ("Upcasting" zu einer nicht erreichbaren Basis mit Referenzen)?

+0

Sie werden bemerken, dass Ihre Basisklasse absichtlich * privat * ist, ja? – WhozCraig

+0

@WhozCraig das ist beabsichtigt, deshalb brauchen wir die Besetzung. Es funktioniert jedoch mit Zeigern. – alex

+0

Nun, die erste (die Referenz) würde sowieso nie aufgerufen werden, und Ihr Compiler hätte Sie davor warnen müssen: clang, zum Beispiel: "Konvertierungsfunktion, die 'Derived' in seine Basisklasse 'Base' konvertiert, wird niemals benutzt werden". – WhozCraig

Antwort

5

[class.conv.fct]/1 liest (Hervorhebung von mir):

A-Umwandlungsfunktion ist nie ein (möglicherweise cv-qualifiziert) Objekt der (möglicherweise cv-qualifiziert) umzuwandeln gleicher Objekttyp (oder eine Referenz darauf), auf eine (möglicherweise cv-qualifizierte) Basisklasse dieses Typs (oder eine Referenz auf es) oder auf (möglicherweise cv-qualifizierte) void.

Und in der Tat Klirren gibt eine Warnung aus:

warning: conversion function converting 'Derived' to its base class 'Base' will never be used 
operator Base&() { 
^ 

Es gibt keine solche Beschränkung für Zeiger, so static_cast<Base*>(d) Werke und ruft den benutzerdefinierten Konvertierungsoperator.

Wenn Sie wirklich den Konvertierungsoperator für Referenzen verwenden möchten, müssen Sie es explizit aufrufen:

std::cout << dRef.operator Base&().fn() << std::endl; 

Aber in diesem Fall werden Sie wahrscheinlich wollen nur eine regelmäßige Memberfunktion für das schaffen, oder sei ehrlich und mache die Erbschaft nur öffentlich.

+2

Oder verwenden Sie die Komposition zur Wiederverwendung anstelle von Vererbung. –

Verwandte Themen