从 int** 到 const int** 的转换

2021-12-13 00:00:00 pointers c++

为什么我会进入这个代码:

Why do I get in this code:

void foo ( const int ** );

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

    return 0;
}

这个错误:

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

我认为可以从非常量转换为常量.

I thought it would be possible to convert from non-const to const.

推荐答案

那是因为你试图从 int** 转换为 const int**

int ** v = new int * [10]; // v is int**
foo(v); //but foo takes const int**

  • int ** 是:指向整数指针的指针".
  • const int ** 是:一个指向常量整数指针的指针".
    • int ** is: "a pointer to a pointer to an integer".
    • const int ** is: "a pointer to a pointer to a constant integer".
    • const 的使用是一个契约,你不能通过两个引用的间接来满足这个契约.

      The use of const is a contract and you cannot meet this contract by going through the indirection of two references.

      来自标准:

      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 总是,只需使用上面的过程.

      so it would be possible to modify const char always, just use procedure above.

      还有:

      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* 指向不同派生类的对象,这可能会导致严重的问题.看看为什么:

      related to this is also invalid conversion Derived** → Base**. If it were legal to convert Derived** → Base**, the Base** could be dereferenced (yielding a Base*), and the Base* could be made to point to an object of a different derived class, which could cause serious problems. See why:

      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
      ");}
        virtual void openGasCap(){printf("Car: open gas cap
      ");}
          virtual void openGasCap2(){printf("Car: open gas cap2
      ");}
            virtual void openGasCap3(){printf("Car: open gas cap3
      ");}
                  virtual void openGasCap4(){printf("Car: open gas cap4
      ");}
      }; 
      class NuclearSubmarine : public Vehicle {
      public:
          int i;
        virtual void startEngine(){printf("Nuclear submarine engine brummm
      ");}
          virtual void fireNuclearMissle3(){printf("Nuclear submarine: fire the missle3!
      ");}
          virtual void fireNuclearMissle(){printf("Nuclear submarine: fire the missle!
      ");}
        virtual void fireNuclearMissle2(){printf("Nuclear submarine: fire the missle2!
      ");}
      };   
      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 
      }
      

相关文章