【问题标题】:C++ placement of 'const' trouble.C++ 放置 'const' 的麻烦。
【发布时间】:2013-12-01 04:47:53
【问题描述】:

首先,我要提前感谢任何回答这个问题的人。非常感谢您的帮助。这是我第一次在这里发帖,如果我发帖不礼貌,请原谅我。

我的问题是关于方法原型的:

void copySubtree(Node<T> * & target, Node<T> * const & original);

当我稍后在combineTrees() 中调用copySubtree() 时。由于代码当前,它会构建。但我最初的想法是:

void copySubtree(Node<T> * & target, const Node<T> * & original);

这给了我错误:

error C2664: 'RootedBinaryTree<T>::copySubtree' : cannot convert parameter 2 from 'RootedBinaryTree<T>::Node<T> *const ' to 'const RootedBinaryTree<T>::Node<T> *&'

我知道当您将const 放在参数中的数据类型之前时,它会阻止您在方法中修改所述参数,但是我不知道将它放在数据类型之后会做什么,我也不知道可以肯定的是,在数据类型之后放置 const 的代码构建不仅仅是侥幸。在数据类型之后放置const 有什么作用?我的代码会以目前的编写方式出现可怕的运行时问题吗?

[另外:我正在尝试编写有根二叉树模板类方法定义(这就是为什么有些方法是空的,并且在cmets中有一些我自己的随机注释)。因此,对于由此造成的任何不便,我深表歉意。]

以下是相关代码:

RootedBinaryTree.h

#ifndef ROOTEDBINARYTREE_H
#define ROOTEDBINARYTREE_H 

template <class T>
class RootedBinaryTree
{
private:
    template <class T>
struct Node
{
    T nodeData;
    Node<T> * leftChild; 
    Node<T> * rightChild; 
}; 
Node<T> * root;
Node<T> * currentPosition; 

void copySubtree(Node<T> * & target, Node<T> * const & original);
void deleteSubtree(Node<T> * n); 

public:
RootedBinaryTree(const T & rootData);
RootedBinaryTree(const RootedBinaryTree<T> & original);
~RootedBinaryTree(); 
void toRoot();
bool moveLeft();
bool moveRight(); 
T getData() const {return currentPosition->nodeData;}; 
RootedBinaryTree<T> & operator=(const RootedBinaryTree<T> & RHS);
void combineTrees(const RootedBinaryTree<T> & leftTree, const RootedBinaryTree<T> & rightTree);
void setNodeData(const T & nodeData); 
};

#endif

RootedBinaryTree.cpp

#ifndef ROOTEDBINARYTREE_CPP
#define ROOTEDBINARYTREE_CPP

#include "RootedBinaryTree.h"

template<class T>
void RootedBinaryTree<T>::copySubtree(Node<T> * & target, Node<T> * const & original) 
{
    // later add something here to delete a subtree if the node we are trying to assign to has children
    // perhaps a deleteSubtree() method

    target = new Node<T>; 
    if(original->leftChild != 0L)
    {
        copySubtree(target->leftChild, original->leftChild); 
    } 
    else
    {
        target->leftChild = 0L; 
    }
    // ^^^ copy targets left (and right) children to originals
    if(original->rightChild != 0L) 
    {
        copySubtree(target->rightChild, original->rightChild);
    }
    else
    {
        target->rightChild = 0L; 
    }
    target->nodeData = original->nodeData;

}

template <class T> 
void RootedBinaryTree<T>::deleteSubtree(Node<T> * n)                                                // Done 
{// Assumes that n is a valid node. 
    if(n->leftChild != 0L) deleteSubtree(n->leftChild);                                             // Delete all nodes in left subtree
    if(n->rightChild != 0L) deleteSubtree(n->rightChild);                                           // Delete all nodes in right subtree 
    delete n; 
}

template <class T>
RootedBinaryTree<T>::RootedBinaryTree(const T & rootData)                                           // Done
{
    root = new Node <T>; 
    root->leftChild = 0L; 
    root->rightChild = 0L; 
    root->nodeData = rootData; 
    currentPosition = root; 
}

template <class T>
RootedBinaryTree<T>::RootedBinaryTree(const RootedBinaryTree<T> & original)
{

}

template <class T>
RootedBinaryTree<T>::~RootedBinaryTree()
{
    deleteSubtree(root);                                                                            // root will be valid because of our constructor and other methods
    root = currentPosition = 0L;    
}

template <class T>
void RootedBinaryTree<T>::toRoot()                                                                  // Done
{
    currentPosition = root; 
}

template <class T>
bool RootedBinaryTree<T>::moveLeft()                                                                // Done 
{
    if(currentPosition->leftChild == 0L) return false; 
    currentPosition = currentPosition->leftChild; 
    return true; 
}

template <class T>
bool RootedBinaryTree<T>::moveRight()                                                               // Done 
{
    if(currentPosition->rightChild == 0L) return false; 
    currentPosition = currentPosition->rightChild;
    return true; 
}

template <class T>
RootedBinaryTree<T> & RootedBinaryTree<T>::operator=(const RootedBinaryTree<T> & RHS)
{

}

template <class T>
void RootedBinaryTree<T>::combineTrees(const RootedBinaryTree<T> & leftTree, const RootedBinaryTree<T> & rightTree)
{ // Copies leftTree into root's left tree and rightTree into root's right tree.
    if(root->leftChild != 0L) deleteSubtree(root->leftChild);
    if(root->rightChild != 0L) deleteSubtree(root->rightChild); 
    copySubtree(root->leftChild, leftTree.root);
    copySubtree(root->rightChild, rightTree.root);
}

template <class T>
void RootedBinaryTree<T>::setNodeData(const T & nodeData)
{
    currentPosition->nodeData = nodeData; 
}

#endif

再次感谢!

【问题讨论】:

  • 您应该知道,“在数据类型之前”是为视觉清晰而提供的一种语言细节:const Type varType const var 是同义词。当您开始将指针和引用混在一起时,语法会变得更加有趣。以const Type* varType const* var 为例
  • 阅读 Retired Ninja's 链接的回复后,我想我明白现在的区别是什么,但我仍然不确定这是否是我想要的代码。即,我知道它可以构建,但它会导致运行时问题吗?
  • 另外:感谢 WhozCraig 的澄清

标签: c++ templates constants parameter-passing pass-by-reference


【解决方案1】:

规则是const 附着在它左边的东西上,如果左边没有任何东西,它就附着在右边的东西上。所以在这种情况下,我们有:

const Node *p; // p is a pointer to a const Node
Node const *p; // same again, p is a pointer to a const Node
Node * const p; // p is a const pointer to a (mutable) Node
const Node * const p; // p is a const pointer to a const Node
Node const * const p; // same again, p is a const pointer to a const Node

大多数人写const Type,因为这是我们对他们的看法,但有些人更喜欢写Type const,因为这条规则。

【讨论】:

  • 参见this (admittedly self-authored) diatribe 关于const 通过两个间接级别的扩展。这是一个地狱图=P(我最喜欢的是char const *const *const p
  • 谢谢!我现在明白了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
  • 2015-09-01
  • 2016-03-02
相关资源
最近更新 更多