2013-05-05 68 views
6

爲什麼我在此代碼得到:轉換** const int的**

void foo (const int **); 

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

    return 0; 
} 

此錯誤:

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

我認爲這將有可能從非const轉換const。

+2

如果foo的原型就是它會被允許:'無效美孚(INT * const的*)' – IronMensan 2013-05-05 23:50:54

+0

我得到'那麼對'foo(int * const *)'的未定義引用。 – user1170330 2013-05-05 23:53:49

+0

您是否也在'foo'的定義中更改了類型? – 2013-05-05 23:54:28

回答

14

那是因爲你正試圖轉換從int** to const int**

int ** v = new int * [10]; // v is int** 
foo(v); //but foo takes const int** 
  • int **是:「一個指針的指針整數」。
  • const int **是:「一個指向常量整數指針的指針」。

使用const是一個合同,您不能通過兩個引用的間接符合該合同。

從標準:

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? 

所以這將是可以修改const char總是,只是使用上述過程

而且也:

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

不錯,從下面的鏈接引用:

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

有關這也是無效的轉換Derived** → Base**。如果轉換Derived** → Base**是合法的,則可以取消Base**(產生Base*),並且可以使Base *指向不同派生類的對象,這可能導致嚴重問題。爲什麼:

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

考慮:

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

你被這裏誤導C++的指針混淆解析規則。這可能是更清楚的看是這樣的:

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

    return 0; 
} 

什麼FOO()參數列表的承諾是,你的指針被傳遞到(指針到恆定的東西)。但是新的int * [10]的意思是「指針指向不是常量的指針」。

所以,如果富被這樣定義:

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

而我想你期待的是

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 
} 

,但它不是,你聲明爲常數P,它的東西它指向。

無論如何,只要在這種情況下使用typedef,一切都將清晰可讀。

5

只能在similiar指針類型之間的轉換,如果你添加常數各級從CV的第一個區別添加常量資格資格和起來。

因此,您可以將int**轉換爲int const* const*,但不能轉換爲int const* *。如果允許省略在中間水平增加常量,你將能夠做這樣的事情:

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 
相關問題