2017-01-18 6 views
1

Ich habe eine Klasse mit einem Konstruktor, der eine nicht-const Referenz, die einem Mitglied der Klasse zugeordnet ist, nimmt. Jetzt möchte ich ein const-Objekt der Klasse erstellen, aber der Konstruktor beschwert sich, wenn ich eine const-Referenz an den Konstruktor übergebe. Der Code unten, der eine Vereinfachung meines ursprünglichen Codes darstellt, zeigt das Problem.Konstruieren von const-Objekt mit nicht-const

Soweit ich sagen kann, sollte es keine Probleme mit der Erstellung eines const Objekts, da es auf const Daten basiert?

Wie kann ich erreichen, was ich versuche in create_const_a zu tun?

#include <iostream> 

class A { 
private: 
    double &d; 
    const int &i; 
public: 
    A(double &dd, const int &ii) 
    : d(dd), i(ii) 
    {} 

    void set_d(double a) { 
    d = a; 
    } 

    void print() const { 
    std::cout << d << " " << i << std::endl; 
    } 
}; 


A create_a(double &dd, const int &ii) { 
    return A(dd,ii); 
} 

const A create_const_a(const double &dd, const int &ii) { 
    return A(dd,ii); 
} 


void foo(A a) 
{ 
    a.set_d(1.3); 
    a.print(); 
} 

void bar(const A a) 
{ 
    a.print(); 
} 


int main(int argc, char *argv[]) 
{ 
    double d = 5.1; 
    int i = 13; 

    foo(create_a(d,i)); 

    bar(create_const_a(d,i)); 

    return 0; 
} 

Der Fehler, den ich bekommen ist:

test.cc: In function ‘const A create_const_a(const double&, const int&)’: 
test.cc:27:17: error: binding ‘const double’ to reference of type ‘double&’ discards qualifiers 
    return A(dd,ii); 
       ^
test.cc:8:3: note: initializing argument 1 of ‘A::A(double&, const int&)’ 
    A(double &dd, const int &ii) 
^

Update: Nach ein paar neue Dinge zu lernen, wie const arbeitet mit Objekten und nicht konstanten Referenzen in ihnen, ich löste schließlich das ursprüngliche Problem durch Einführung eines anderen Typs, beispielsweise ConstA, der nur const-Referenzen enthält, die dann in jedem der problematischen Fälle verwendet werden könnten.

+1

Sie können von nicht-const zu const gehen, aber nicht umgekehrt. Der Konstruktor benötigt eine nicht-const, und Ihre 'create_const_a' erhält eine const. – AndyG

+5

All diese Referenzen ... Wenn Sie fortfahren, werden Sie früher oder später zu einem Zeiger kommen, wo Sie eine hängende Referenz haben und schlimme Dinge passieren werden. * Warum * hast du Referenzen in der A-Klasse? Was ist das * aktuelle * Problem, das Sie mit einer solchen Lösung lösen möchten? –

+1

Ihre Methode 'create_const_a' gibt einen Verweis auf ein lokales Objekt zurück. Das funktioniert nicht so, wie du denkst. Weitere Informationen finden Sie [diese Antwort] (http://stackoverflow.com/a/4643721/7359094). –

Antwort

1

C++ verbietet dies die Konvertierung von const Verweis auf nicht-const.

Hier ist ein kleines Beispiel dafür, wie dies geschehen würde:

struct foo { 
    int& a; 
    foo(int& b) : a(b) {} 
    void bar() const { 
     a = 5; 
    } 
}; 

Die obige gut kompiliert, weil a = 5 tut nicht Änderung der Zustand des foo Objekts; es ändert den Zustand eines externen int, so dass foo::barconst sein darf.

Nehmen wir nun an, dass wir dies tun könnte:

const foo make_const(const int& x) { 
    return foo(x); // Not allowed 
} 

Dann würden wir in der Lage sein

const foo f(make_const(10)); 
f.bar(); 

zu schreiben und einen Verweis auf eine temporäre int, modifizieren, die nicht definiertes Verhalten ist. Hier

ist ein kleines demo:

int x = 10; 
cout << x << endl; 
const foo f(x); 
f.bar(); 
cout << x << endl; 

Er druckt

10 
5 
+0

Die Tatsache, dass die Referenz geändert werden kann, ohne die const-Korrektheit zu verletzen, war für mich völlig neu und erklärt viel darüber, warum dies unmöglich erscheint. – kalj

+0

@kalj Das ist der schwierigste Teil von 'const'-ness, wenn es auf Referenzen und Zeiger angewendet wird. Ein Zeiger oder eine Referenz kann "const" sein, während das Element, auf das sie verweisen/referenziert, schreibbar bleiben würde. – dasblinkenlight

0

Sie versuchen const ness fallen:

const A create_const_a(const double &dd, const int &ii) { 
    return A(dd,ii); 
} 

aber dd ist eine nicht-const, so das erstellte Objekt A würde nicht wissen, dass ich t kann sein d Mitglied nicht ändern, während der Aufrufer von create_const_a die Variable glauben würde, die so geht.

Sie können nicht mit sich machen eine Kopie dd oder Fallenlassen der const (zum Beispiel durch einen const_cast) gehen um was gefährlich ist und zeigt stark ein Fehler im Design.

Ihre Definition von A sagt "Ich muss in der Lage sein zu ändern d", aber in der create_const Sie versprechen, dass es nicht geändert wird.

Mit anderen Worten, Sie sollten den Fehler im Design beheben. Entweder die Einschränkung aufheben oder eine Kopie erstellen. Den "Fehler weggehen" zu machen, wird nur das Symptom des schlechten Designs zum Schweigen bringen, bis Sie in echte Schwierigkeiten geraten werden, wenn der Vertragsbruch zu Rückwirkungen führt.

0

Die Funktion const A create_const_a nimmt als erstes Argument ein ref zu einem const double und versucht dann, es in ctor als nicht const ref zu verwenden, was nicht erlaubt ist.

Sie sollten den const Qualifier hier entfernen.

Wenn Sie wirklich sicher, warum Sie es hier tun können, das heißt, wenn Sie sicher sein können, dass create_const und wird immer nicht const Parameter erhalten, können Sie explizit const_cast verwenden die Qualifikation zu entfernen:

const A create_const_a(const double &dd, const int &ii) { 
    return A(const_cast<double &>(dd),ii); 
} 

Aber BEWARE, führt dies zu Undefined Behavior, wenn Sie das für eine Variable tun, die ursprünglich als const deklariert wurde.

Verwandte Themen