2017-02-14 65 views
3

我有以下的底座和继承的类:为什么指针的这个引用是右值?

// Abstract base class Manager. 
class Manager 
{ 
public: 
    Manager(Task*& _task); 
protected: 
    // Reference of a pointer to the current task. 
    Task*& task; 
}; 

// Abstract base class Task. 
class Task 
{ 
    virtual task_rcodes_t run() = 0; 
protected: 
    uint8_t task_id; 
}; 

// Still abstract class Special_Task. 
class Special_Task : public Task 
{ 
public: 
    Special_Task(); 
}; 

// Class Special_Manager. 
class Special_Manager : public Manager 
{ 
public: 
    Special_Manager(); 
protected: 
    // Pointer to the current special task. 
    Special_Task* task; 
}; 

的想法是让任务指针,以检测没有当前任务运行是0。为了对Task和Spe​​cial_Task指针有共同的访问权限,它们通过引用传递给指针。

为什么我收到错误信息: “的类型的非const引用无效初始化‘任务 &’从类型‘Special_Task *’的右值” 结合: “符号“经理“无法解析”

为Special_Manager的构造:

// Constructor Manager 
Manager::Manager(Task*& _task) : task (_task) 
{} 

// Constructor Special_Manager 
Special_Manager::Special_Manager() : Manager(task), task (0) 
{} 

由于Special_Task *任务是正常的(指针)VARI能够,我不明白为什么它被认为是一个右值?

谢谢!

+0

因为它不是左值,因为你不能分配给引用。 – EJP

+0

什么是'Special_Manager();'类'Manager_Special'内部? –

+0

这就是构造函数。我更正了班级名称中的打字错误。 – nubert

回答

3

由于Special_Task *任务是一个正常(指针)变量,我不明白为什么它被认为是一个右值?

任何左值可以通过隐式转换转换为右值。 task是一个左值,因为它是“范围内变量的名称”(请参阅​​cppreference on value categories),并且在您的示例中将其转换为右值。

但是在这种情况下,整个左值/右值主要是红鲱鱼。问题是,你正试图将一种类型的指针分配给不同类型的指针引用,错误消息说:

类型的非const引用无效初始化“任务* &”从右值类型的“特殊和下划线;任务*”。

(顺便说一句,我很想知道到底是什么编译器/代码给你的消息,我已经试过所有的gcc版本给代替:从'Task *'类型的右值创建对'Task * &'类型的非常量引用的无效初始化)。

尽管Special_Task是派生类型Task,但不能这样做。它们各自的指针类型不是子类型; Special_Task *不是Task *,因此Task *&-变量不能被指定为Special_Task *。 (可能由于Special_Task *可隐式转换为Task *这一事实而导致一些混淆,但是,需要注意的是,在这种情况下,生成的指针是右值,而不是左值,这解释了后者的错误消息)。

为了说明为什么你不能指定一个Special_Task *Task *&变量,请看下面的例子:

// Other_Task is a second derived class of Task: 
class Other_Task : public Task { /* ... */ } 

Special_Task st; 
Special_Task *p = &st; // ok, p points to st 

Task *& tp = p; // if it were allowed: tp references p 

Other_Task ot; 
tp = &ot;  // now, p points to ot - which is the wrong type 

上述例子表明,为什么不能一个Special_Task *Task *&变量直接分配。因此,在您的代码中,Special_Task *隐式转换为Task *并成为右值,该值也不能分配给非常量引用。该示例还说明了为什么const引用会正常:它会阻止导致p指向错误类型的对象的分配。

回到你的问题:多观察,因为没有必要在Managertask做个参考,简单的解决方法是它的声明更改为简单的指针:

Task* task; 

并改变构造:

Manager(Task* _task); 

的替代解决方案,但没有一个我建议,将类型更改为const参考:

Task * const & task; 

Manager(Task* const & _task); 

哦,还有一两件事:

Special_Manager::Special_Manager() : Manager(task), task (0) 

这传递的taskManager构造未初始化的值,然后初始化task 0.1相反,你应该写:

Special_Manager::Special_Manager() : Manager(0), task (0) 
+0

_“如错误消息所示”_不,如果您查看问题的Markdown,您会看到这是一个格式错误。 OP没有逃避'*'。 –

+0

@LightnessRacesinOrbit谢谢,修正。在另一个错误消息中还有另一个缺失的*(以某种方式),我也修复了这个问题。书面内容适用于实际的错误信息(即回答站)。 – davmac

+0

更改为const将不允许我在执行期间分配任务= 0,对吗?另外,我可以像你说的那样在Manager类中使用普通的Task指针,在Special_Manager中避免额外的Special_Task指针,并且如果需要来自Special_Task的功能,只需在Task指针上使用reinterpretcast! – nubert

1

的错误是在这里:

Special_Manager::Special_Manager() : Manager(task), task (0) 
{} 

0被认为是rvalue或者是铸造为Task*&&类型的int&&。这是可能的,因为0被认为是可用于指针转换值的有效形式。但是因为构造函数仅使用Task*&,所以它不能采用值为0的铸造形式,因此编译器会拒绝该代码。

如果你做的类型const Task*&的构造函数的参数,代码再编译,因为const Task*&是与Task*&&类型兼容。

+2

该错误与'0'无关。从代码中删除'task(0)',你仍然会得到相同的编译器错误。 – davmac

+0

另外:_如果你想让类型为const的构造函数参数Task *&_ - 是错误的。 'Task * const&'将是合适的类型。引用本身必须是'const'。 – davmac

1

要扩大davmac的答案:

  • 如果YX子类,则:

    • 一个参考-TO-X真的可以指Y。同样地,
    • a 指针可以指向X可以指向Y

    然而,类型指针-TO-X指针-TO-Y以同样的方式XY相关本身并不相关,因此

    • 一个指针 - 指向X不能指向指针指向Y(虽然指向最终的指向X所能指向一个Y),和
    • 一个参考到指针-TO- X不能指指针TO- Y任一。

比较模板实例,其中尽管XY的关系std::vector<X>std::vector<Y>是不是在所有相关的。


具体地说,参考到指针-TO- Task不能指指针-TO-Special_Task

相关问题