上传指针参考

时间:2009-12-22 21:01:34

标签: c++ inheritance pointers reference upcasting

我有以下设计的例子(来自实际代码):

template <class T>
class Base {
public:
 Base(int a):x(a) {}
    Base(Base<T> * &other) { }
    virtual ~Base() {}
private:
 int x;
};

template <class T>
class Derived:public Base<T>{
public:
  Derived(int x):Base<T>(x) {}
  Derived(Derived<T>* &other): Base<T>(other) {}

};


int main() {
 Derived<int> *x=new Derived<int>(1);
 Derived<int> y(x);
}

当我尝试编译时,我得到:

1X.cc: In constructor ‘Derived<T>::Derived(Derived<T>*&) [with T = int]’:
1X.cc:27:   instantiated from here
1X.cc:20: error: invalid conversion from ‘Derived<int>*’ to ‘int’
1X.cc:20: error:   initializing argument 1 of ‘Base<T>::Base(int) [with T = int]’

1)显然gcc被构造函数混淆了。如果我删除了引用 从构造函数,然后代码编译。所以我的假设是出了问题 使用向上转换指针引用。有人能告诉我这里发生了什么吗?

2)一个稍微不相关的问题。如果我要在构造函数中做一些可怕的事情,比如“删除其他”(跟我一起), 当有人通过我指向堆栈上某些东西的指针时会发生什么?

E.g. Derived<int> x(2);
     Derived<int> y(x);

where 

 Derived(Derived<T>*& other) { delete other;}

如何确保指针合法地指向堆上的某些内容?

5 个答案:

答案 0 :(得分:10)

Base<T>Derived<T>的基本类型,但Base<T>*不是Derived<T>*的基本类型。您可以传递派生指针代替基指针,但不能传递派生指针引用来代替基指针引用。

原因是,假设你可以,并假设Base的构造函数在引用中写了一些值:

Base(Base<T> * &other) {
    Base<T> *thing = new Base<T>(12);
    other = thing;
}

您刚刚将指针指向 not a Derived<T>的指针,指向Derived<T>。编译器不能让这种情况发生。

答案 1 :(得分:3)

  1. 您无法将对Derived指针的引用转换为对Base的指针的引用。 (模板不会对此问题做出贡献,因此请从下面的示例中删除。)
  2. 如果要推迟指针的责任,请使用智能指针类型。智能指针类型可以表示原始指针不能“删除”的责任。示例包括std :: auto_ptr和boost::shared_ptr等等。
  3. 为什么你不能上传指针引用:

    struct Base {};
    struct Derived : Base {};
    struct Subclass : Base {};
    
    int main() {
      Derived d;
      Derived* p = &d;
      Derived*& d_ptr = p;
    
      Base*& b_ptr = d_ptr; // this is not allowed, but let's say it is
    
      Base b;
      b_ptr = &b; // oops! d_ptr no longer points to a Derived!
    
      Subclass s;
      b_ptr = &s; // oops! d_ptr no longer points to a Derived!
    }
    

    当您将“其他”参数传递给Base ctor时,您尝试执行与上面b_ptr = d_ptr相同的操作。

答案 2 :(得分:2)

通过在文档中写入指针并依赖调用者遵守指针,确保指针指向堆上的某些内容。如果调用你的构造函数的人传递了一个堆栈指针,那么所有的投注都会被关闭,这不是你的错 - 你可以尽早解决问题,但不能保证。

这就是标准库的工作方式 - 通常它会捕获明显的错误,但它并不是必需的,并且由调用者确定他们没有做任何愚蠢的事情。

答案 3 :(得分:0)

您的x变量不是指针,如果您要为其指定new Derived<int>,则该指针应为。

至于删除堆栈中的东西,不要这样做。没有办法判断你是否已经在堆栈或堆上传递了某些东西的地址(实际上,C ++标准甚至不承认存在堆栈)。这里的教训是你不应该删除你不拥有的东西,特别是如果你无法告诉他们来自哪里。

答案 4 :(得分:0)

不确定为什么要引用指针。为什么不

Base(Base<T> * other) { }

Derived(Derived<T>* other): Base<T>(other) {}

这应该有效。

而且,和其他人一样,我认为你不能合理地知道指针是否指向堆。

编辑:为什么不能做你想做的事情:考虑例子:

Derived1<int> *x = new Derived1<int>
Base<int> **xx =&x;
Derived2<int> y;
*xx = &y;

Derived1和Derived2是否来自Base的不同的类?你认为这是合法的吗?现在Derived1 *类型的x指向Derived2?