Home > Net >  Double becomes pointer when returned?
Double becomes pointer when returned?

Time:10-08

I'm new to Cpp and I'm just trying to construct a very basic 'Circle' class. Below is my code

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

The code runs and behaves as expected. However, if, in the return line to the method get_attr, I replace *circle_attr with circle_attr , then I get the error cannot convert 'double*' to 'double' in return. However, circle_attr is already an array of doubles. That's what I intialised it as and it's what Cpp is telling me, since when I call typeid(circle_attr).name() I get back A3_d, which I assume is short for Array3_double. So what is going on here?

CodePudding user response:

The actual issue you're having is the attempt to return a C-array from a function. That's not a thing that can be done. If you want, the smallest possible change would be to change your function to look like this:

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

You stated that your function was supposed to return A double, and then you tried returning an array of doubles, or really just the radius in your case.

std::array is a bit of a mess, though, since the size is part of the type information.

Here's your code, with some tweaks to get it more in line with C and also completely rewriting your get_attr() function.

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

Output:

Radius: 5
Area: 78.5398
Perimieter: 31.4159

We added constructors, which are a fundamental part of C OOP. You can see in main() how constructors allow us to initialize at the declaration site.

I also left one your original lines in main() to note that even if get_attr() worked, you didn't save the info at all. So you wouldn't have had it anyway.

Your get_attr() function has been written to take advantage of a C 17 feature called structured bindings. It also takes advantage of another feature called CTAD, just to keep the one line in get_attr() succinct.

In order for you to test this, you'll need to add the -std=c 17 flag to the compile command you're using. It's good practice to always specify the standard version you're using.

  • Related