我有以下人为的示例(来自真实代码):

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;}

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

有帮助吗?

解决方案

Base<T>Derived<T>的基类型,但Base<T>*不是Derived<T>*的基类型。可以传递派生的指针代替基指针的,但不能代替基指针参考的传递派生的指针参考。

的原因在于,假设你可以,并假设基地的构造是写一些值到参考:

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

您刚刚写指针的东西是的的一个Derived<T>,成指针Derived<T>。编译器不能让这种情况发生。

其他提示

  1. 不能将对 Derived 指针的引用转换为对 Base 指针的引用。(模板不会造成这里的问题,因此从下面的示例中删除。)
  2. 如果您想推迟对指针的责任,请使用智能指针类型。智能指针类型可以代表原始指针所不能的“删除责任”。示例包括 std::auto_ptr 和 升压::shared_ptr, 等等。

为什么不能向上转换指针引用:

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 多于。

您确保指针指向写你的文档中,并依靠来电者通过遵守东西就堆。如果谁调用构造函数传递一个堆栈指针,全盘皆输,这不是你的错 - 你可以尝试及早发现问题,但不能保证

这是如何的标准库的作品 - 往往会抓住明显的错误,但它并不需要,而且它是由主叫方,以确保他们没有做任何愚蠢的事

x变量不是指针,它应该是,如果你想一个new Derived<int>分配给它。

至于在堆栈上删除的事,不这样做。有没有办法告诉你是否已通过堆栈或堆(事实上,C ++标准甚至不承认一个栈的存在)的东西的地址。这里的教训是,你不应该删除的东西,你不拥有,特别是如果你没有告诉他们来自何处的方式。

不知道你为什么要参考指针。为什么不

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的被不同类从碱衍生?你会认为这是合法的?现在的类型Derived1 *点是x到Derived2的?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top