2013-05-05 19 views
6

Perché ricevo in questo codice:conversione da int ** a const int **

void foo (const int **); 

int main() { 
    int ** v = new int * [10]; 
    foo(v); 

    return 0; 
} 

questo errore:

invalid conversion from ‘int**’ to ‘const int**’ [-fpermissive]| 

ho pensato che sarebbe stato possibile convertire da non const a const.

+2

Sarebbe consentito se il prototipo di foo era: 'vuoto foo (int * const *)' – IronMensan

+0

ottengo 'riferimento non definito a' foo (int * const *) 'quindi. – user1170330

+0

Hai cambiato il tipo anche nella definizione di 'foo'? –

risposta

14

è perché si sta tentando di convertire da int** to const int**

int ** v = new int * [10]; // v is int** 
foo(v); //but foo takes const int** 
  • int ** è: "un puntatore a un puntatore a un intero".
  • const int ** è: "un puntatore a un puntatore a un numero intero costante".

L'uso di const è un contratto e non è possibile soddisfare questo contratto passando attraverso l'indirezione di due riferimenti.

dalla norma:

const char c = 'c'; 
char* pc; 
const char** pcc = &pc; // not allowed (thankfully!) 
       ^^^ here the bundit is hidden under const: "I will not modify" 
*pcc = &c;    // *pcc is "pointer to const" right? so this is allowed... 
*pc = 'C';    // would allow to modify a const object, *pc is char right? 

quindi sarebbe possibile modificare const charsempre, basta usare sopra procedura.

E anche:

char *s1 = 0; 
const char *s2 = s1; // OK... 
char *a[MAX]; // aka char ** 
const char * const*ps = a; // no error! 

bello citare dal link sottostante:

By way of analogy, if you hide a criminal under a lawful disguise, he can then exploit the trust given to that disguise. That's bad.

http://www.parashift.com/c++-faq-lite/constptrptr-conversion.html

relative a questo è anche la conversione non valida Derived** → Base**. Se fosse legale convertire Derived** → Base**, il Base** potrebbe essere sottoposto a dereferenziazione (ottenendo un valore Base*) e Base * potrebbe essere indirizzato a un oggetto di una classe derivata diversa, che potrebbe causare seri problemi.Capire perché:

class Vehicle { 
public: 
    virtual ~Vehicle() { } 
    virtual void startEngine() = 0; 
}; 

class Car : public Vehicle { 
public: 
    virtual void startEngine(); 
    virtual void openGasCap(); 
}; 

class NuclearSubmarine : public Vehicle { 
public: 
    virtual void startEngine(); 
    virtual void fireNuclearMissle(); 
}; 

int main() 
{ 
    Car car; 
    Car* carPtr = &car; 
    Car** carPtrPtr = &carPtr; 
    Vehicle** vehiclePtrPtr = carPtrPtr; // This is an error in C++ 
    NuclearSubmarine sub; 
    NuclearSubmarine* subPtr = ⊂ 
    *vehiclePtrPtr = subPtr; 
    // This last line would have caused carPtr to point to sub ! 
    carPtr->openGasCap(); // This might call fireNuclearMissle()! 
    ... 
} 

http://www.parashift.com/c++-faq-lite/derivedptrptr-to-baseptrptr.html

considerare:

class Vehicle { 
public: 
    virtual ~Vehicle() { } 
    virtual void startEngine() = 0; 
}; 
class Car : public Vehicle { 
public: 
    virtual void startEngine(){printf("Car engine brummm\n");} 
    virtual void openGasCap(){printf("Car: open gas cap\n");} 
    virtual void openGasCap2(){printf("Car: open gas cap2\n");} 
     virtual void openGasCap3(){printf("Car: open gas cap3\n");} 
      virtual void openGasCap4(){printf("Car: open gas cap4\n");} 
}; 
class NuclearSubmarine : public Vehicle { 
public: 
    int i; 
    virtual void startEngine(){printf("Nuclear submarine engine brummm\n");} 
    virtual void fireNuclearMissle3(){printf("Nuclear submarine: fire the missle3!\n");} 
    virtual void fireNuclearMissle(){printf("Nuclear submarine: fire the missle!\n");} 
    virtual void fireNuclearMissle2(){printf("Nuclear submarine: fire the missle2!\n");} 
}; 
int main(){ 
    Car car; Car* carPtr = &car; 
    Car** carPtrPtr = &carPtr; 
    //Vehicle** vehiclePtrPtr = carPtrPtr; // This is an error in C++, But: 
    Vehicle** vehiclePtrPtr = reinterpret_cast<Vehicle**>(carPtrPtr); 
    NuclearSubmarine sub; NuclearSubmarine* subPtr = &sub; 
    *vehiclePtrPtr = subPtr; // carPtr points to sub ! 
    carPtr->openGasCap(); // Nuclear submarine: fire the missle3! 
    carPtr->openGasCap2(); // Nuclear submarine: fire the missle! 
    carPtr->openGasCap3(); // Nuclear submarine: fire the missle2! 
    //carPtr->openGasCap4(); // SEG FAULT 
} 
2

Qui vieni ingannato dalle regole di analisi confusionaria del C++ per i puntatori. Potrebbe essere più chiaro a guardare in questo modo:

typedef const int * ptr_to_const_int; 
void foo(ptr_to_const_int *); 
int main() { 
    int ** v = new int * [10]; 
    foo(v); 

    return 0; 
} 

Che foo (s ') lista di parametri promette è che ti verrà passandogli un puntatore ad un (puntatore a costante cosa). Ma new int * [10] significa "puntatore a (puntatore-a-non-costante-cosa)".

Quindi, se foo fosse definito in questo modo:

foo(const int **p) 
{ 
    (*p); //<-- this is actually of type const int * 
} 

mentre penso che ci si aspetta che

foo(const int **p) 
{ 
    (*p); //<-- you're expecting this to be of type int * 
    p = 0; //<-- and this to throw a compiler error because p is const 
} 

ma non è p che si sta dichiarando di essere costante, è la cosa punta a.

In ogni caso basta usare un typedef in questo caso e tutto sarà chiaro e leggibile.

5

si può solo aggiungere qualificazione const in una conversione tra i tipi di puntatore simile se si aggiunge const a tutti i livelli dalla prima differenza di cv qualificazione e fino.

Quindi, è possibile convertire int** a int const* const*, ma non a int const* *. Se fosse consentito omettere const aggiunta a livelli intermedi si sarebbe in grado di fare qualcosa di simile:

const int c = 29; 
int *pi; 
const int** ppci = &pi; // only adding const, right 
*ppci = &c; 
*pi = 0; // changing c ?! but no const_cast in sight