为啥这个 const auto 变量在 range-for 循环中为类的 const 成员函数编译?

Posted

技术标签:

【中文标题】为啥这个 const auto 变量在 range-for 循环中为类的 const 成员函数编译?【英文标题】:Why is this const auto variable in a range-for loop compiling for a const member function of a class?为什么这个 const auto 变量在 range-for 循环中为类的 const 成员函数编译? 【发布时间】:2020-04-15 03:04:39 【问题描述】:

我有以下类声明,根据我所学的有关 const 成员函数的知识,const 对象不能调用非 const 成员函数。在 range-for 循环中,我们使用的是“const auto animal”,假设它使用的是 const 对象,所以我认为 const 对象在调用非 const 成员函数 speak() 时应该会给出编译错误,但它实际编译,为什么?,也许我不清楚 range-for 循环是如何工作的......谢谢!

#include <iostream>
#include <string>

class Animal 
protected:
     std::string name_;
     std::string speak_;
public:
    Animal(const std::string &name, const std::string &speak) : name_(name), speak_(speak)
    const std::string &getName() const   return name_;
    std::string speak()   return speak_;
;

class Cat : public Animal
public:
 Cat(const std::string &name) : Animal(name, "meow")
;

class Dog : public Animal
public:
 Dog( const std::string &name) : Animal(name, "woof")
;

int main() 
    Cat tom "tom" ;
    Dog felix "felix" ;

    Animal *animals[] &tom, &felix;
     for (const auto &animal : animals)
         std::cout << animal->getName() << " says " << animal->speak() << '\n';


    return 0;

【问题讨论】:

所有的魔法都在auto之下。如果您尝试在其中打开,您会看到这是对常量指针的引用,而不是对常量指针的引用。这就是为什么你可以调用 Animal 的非 const 方法 【参考方案1】:

这里的const auto&amp; 变成了对Animal* 类型变量的常量引用。这意味着您无法更改指针指向的位置,但指向的值本身仍然是可变的。

替换 auto 如下所示:

for (Animal* const& animal : animals)
  // ...

【讨论】:

嗨!谢谢,这回答了我的问题,但它提出了另一个问题......你怎么能舒尔,或者你怎么知道这是“自动”正在采取的形式(除了它以这种方式工作的事实)。我的意思是,我也可以认为 auto 正在考虑(const Animal *animal)......这实际上是我发布这个问题的原因 @fespin 您可以使用static_assert(std::is_same_v&lt;decltype(animal), Animal *const &amp;&gt;); 进行验证。还有一些特定于编译器的方法来打印变量的类型,例如coliru.stacked-crooked.com/a/8b6d0e588c0eb0cb 您要循环的整个类型是Animal*。然后,auto 变成了Animal*,我们在其中添加了一个 const 引用。一种考虑方法是将Animal* 替换为using animal_ptr = Animal*;然后,const auto&amp; 变为 const animal_ptr&amp;:也就是说,指针是 const,而不是内部发生的任何内容。 在您想到const Animal* 时,const 会以某种方式需要在内部指针中移动;也就是说,它需要进入animal_ptr。另一方面,Animal* const 是正确的。 (请记住,const 适用于其左侧的内容,除非左侧没有任何内容,然后它直接应用于右侧的内容。)

以上是关于为啥这个 const auto 变量在 range-for 循环中为类的 const 成员函数编译?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 lambda auto& 参数选择 const 重载?

C语言中auto,register,static,const,volatile的区别

const常量不能被修改,为啥编译还能通过?

算法笔记 C++中const和auto的那些事 HERODING的算法之路

为啥允许在这里用非 const 初始化静态变量?

在 Delphi 中,为啥传递接口变量有时需要它是 const 参数?