【问题标题】:Double becomes pointer when returned?返回时 Double 变成指针?
【发布时间】:2021-11-27 01:22:52
【问题描述】:

我是 Cpp 的新手,我只是想构建一个非常基本的“Circle”类。下面是我的代码

#include <iostream> 
#include <cmath>
#include <typeinfo> 

class Circle { 
    
    private: 
    const double pi = 3.14159265358979323846;
    double radius;
    double area; 
    double perimeter;  
    public: 
    void set_rad(double rad){ 
        radius = rad; 
        area = pi*pow(rad,2); 
        perimeter = 2*pi*rad;  
        
        
    }

    double get_attr() {
        double circle_attr[3] = {radius, area, perimeter}; 
        std::cout << typeid(circle_attr).name() << std::endl; 

        return *circle_attr; 
    }
}; 

int main(){ 
   
    Circle aCircle;
    aCircle.set_rad(5);
    aCircle.get_attr();
    return 0;
}

代码运行并按预期运行。但是,如果在方法get_attr 的返回行中,我将*circle_attr 替换为circle_attr,那么我会收到错误cannot convert 'double*' to 'double' in return。但是,circle_attr 已经是一个双精度数组。这就是我将它初始化的内容,也是 Cpp 告诉我的内容,因为当我调用 typeid(circle_attr).name() 时,我会返回 A3_d,我认为它是 Array3_double 的缩写。那么这里发生了什么?

【问题讨论】:

  • 问问自己:双精度数组与单个双精度数相同吗?至于为什么编译器认为你的数组现在是一个指针,见:stackoverflow.com/questions/1461432/…
  • 当然可以,但是如果我想让一个函数返回一个双精度数组,我还能如何声明它呢?
  • 如果您可以使用 C++11 或更高版本,则切换到使用 std::array。如果不能,请创建自己的数组类。普通 C 数组是类型系统中的二等公民,如果可以避免此类问题,应避免使用。
  • 这是我会使用struct 的东西。您可以使用几个通用容器,但struct 允许您为所有成员提供易于阅读的名称。一旦你在最近的 C++ 标准中有 structured bindings 就不是那么重要了,但是如果你像我一样坚持老派,那么增加的易读性就值得它的黄金重量。
  • " 如果我​​希望它返回一个双精度数组" --> 代码不能返回原始 array

标签: c++ class pointers types


【解决方案1】:

您遇到的实际问题是尝试从函数返回 C 数组。这不是一件可以做到的事情。如果您愿意,可能的最小更改是将您的函数更改为如下所示:

#include <array>

// [...]

std::array<double, 3> get_attr() {
        std::array<double, 3> circle_attr{radius, area, perimeter}; 
        std::cout << typeid(circle_attr).name() << std::endl; 

        return circle_attr; 
    }

您说您的函数应该返回 A 双精度,然后您尝试返回一个双精度数组,或者实际上只是您的情况下的半径。

std::array 有点混乱,因为大小是类型信息的一部分。

这是您的代码,经过一些调整以使其更符合 C++ 并完全重写您的 get_attr() 函数。

#include <cmath>
#include <iostream>
#include <tuple>  // CHANGED: Needed for structured binding usage in get_attr()

class Circle {
 private:
  const double pi = 3.14159265358979323846;
  double radius = 0.0;  // CHANGED: Kept the default member initialization going
  double area = 0.0;
  double perimeter = 0.0;

 public:
  Circle() = default;  // CHANGED: Added constructors
  Circle(double r)
      : radius(r), area(pi * std::pow(radius, 2)), perimeter(2 * pi * radius) {}

  void set_rad(double rad) {
    radius = rad;
    area = pi * pow(rad, 2);
    perimeter = 2 * pi * rad;
  }

  // CHANGED: Using C++17 feature called structured bindings; also made function
  // const, since it shouldn't alter the data
  auto get_attr() const { return std::make_tuple(radius, area, perimeter); }
};

int main() {
  Circle aCircle(5.0);  // CHANGED: Now we can use constructors
  // aCircle.get_attr();  // NOTE: Didn't even try to save info anywhere
  auto [radius, area, perimeter] = aCircle.get_attr();
  std::cout << "Radius: " << radius << "\nArea: " << area
            << "\nPerimieter: " << perimeter << '\n';

  return 0;
}

输出:

Radius: 5
Area: 78.5398
Perimieter: 31.4159

我们添加了构造函数,这是 C++ OOP 的基本部分。您可以在main() 中看到构造函数如何允许我们在声明站点进行初始化。

我还在main() 中留下了您的原始行,以注意即使get_attr() 有效,您根本没有保存信息。所以无论如何你都不会拥有它。

您的get_attr() 函数已编写为利用称为structured bindings 的C++17 功能。它还利用了另一个名为CTAD 的功能,只是为了保持get_attr() 中的一行简洁。

为了让您对此进行测试,您需要将-std=c++17 标志添加到您正在使用的编译命令中。最好始终指定您使用的标准版本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-12
    • 2010-11-16
    • 1970-01-01
    • 2013-01-12
    • 2017-03-22
    • 2018-04-17
    相关资源
    最近更新 更多