What should the object type be to have a chained call?

72 Views Asked by At

Can someone please tell me what the difference is between the two codes for class Point and class Dog? Dog compiles without any error. Point throws an error if the point object is from the stack and not called via a pointer. Why?

#include <iostream>
#include <string_view>
#include <string>

class Dog{
    public : 
    
        Dog() = default;
        Dog(std::string_view name_param, std::string_view breed_param, int  age_param){
            name = name_param;
            breed = breed_param;
            p_age = new int;
            *p_age = age_param;
    
        }
        void print_info(){
            std::cout << "Dog (" << this << ") : [ name : " << name 
                << " breed : " << breed << " age : " << *p_age << "]" << std::endl;
        }

        //Setters
        //Chained calls using pointers
        
        Dog* set_dog_name(std::string_view name){
            //name = name; // This does nothing
            this->name = name;
            return this;
        }

        Dog* set_dog_breed(std::string_view breed){
            this->breed = breed;
            return this;
        }

        Dog* set_dog_age(int age){
            *(this->p_age) = age;
            return this;
        }
        

    private : 
        std::string name;
        std::string breed;
        int * p_age{nullptr};
};


int main(){

    Dog dog1("Fluffy","Shepherd",2); //Constructor
    dog1.print_info();

    //Chained calls using pointers
    dog1.set_dog_name("Pumba")->set_dog_breed("Wire Fox Terrier")->set_dog_age(4);

    dog1.print_info();

    std::cout << "Done!" << std::endl;
   //Destructor
    return 0;
}
#include <iostream>

class Point{
    public : 
    
    Point() = default;
    Point(double x, double y){
        m_x = x; 
        m_y = y;
    }
    
    void print_point(){
        std::cout << "Point[x : " << m_x << ", y : " << m_y << "]" ;
    }

    Point* set_x(double m_x){
        this->m_x = m_x;
        return this;
    }

    Point* set_y(double m_y){
        this->m_y = m_y;
        return this;
    }

    //member variables
    private : 
        double m_x{1};
        double m_y{1};
};

int main(){
    
    Point p1(1.1, 2.2);
    //Point* p_ptr {&p1}; 
    p1.print_point();
    p1->set_x(21.2)->set_y(4.2); //error.error: base operand of ‘->’ has non-pointer type ‘Point’                                      
    p1.print_point();            //works only if p_ptr->set_x(21.2)->set_y(4.2);
    return 0;
}

I don't understand why the Dog class is working with a regular object, but the Point class needs a pointer.

2

There are 2 best solutions below

0
Mikel F On

As Eljay mentioned in a comment, you are dereference the initial variable differently in the two examples. The original Dog local variable is used properly with the '.' notation for the first call, and then pointer '->' notation for subsequent calls. Point uses the pointer '->' notation from the beginning, causing this error.

0
Vivick On

p1 is an object, not a pointer to an object. Therefore, you need to use the dot operator to access its member variables and member functions. You can't use the arrow operator on an object without it being a pointer, or having overloaded the arrow operator.

If you're going for fluent setters, I suggest you return by reference instead of by pointer, i.e.

Dog& set_dog_name(std::string_view name){
    //...
    return *this;
}