返回*this的成员函数

1.返回引用与非引用的区别

返回引用示例:

#include <iostream>
#include <string>

namespace test_starthis {
    
    class Screen{
    public:
        Screen() = default;
        Screen(int x, int y, std::string contents): x_(x), y_(y), contents_(contents), ct_(0){
            std::cout << "Screen ctor with parameter called." << std::endl;
        }
        
        // 类内实现,默认inline
        Screen& set(std::string new_contents){
            contents_ = new_contents;
            
            return *this;
        }
        Screen& move(int x, int y) {
            x_ = x;
            y_ = y;
            
            return *this;
        }
        
        // 从const函数返回的对象是const对象,因此返回值也需要加const
        const Screen& display() const {
            std::cout << "contents_: " << contents_ << std::endl;
            std::cout << "x_: " << x_ << ", y_: " << y_ << std::endl;
            
            ++ct_;  // 虽然函数是const,但由于ct_被mutable修饰了,因此可以修改ct_
            
            std::cout << "The screen is displayed " << ct_ << " times." << std::endl;
            
            return *this;   // *this是const对象
        }

    private:
        int x_ = 0;
        int y_{0};;
        std::string contents_{"my screen"};
        mutable unsigned int ct_{0};  // 如果想在const成员函数内修改类的某个数据成员,可在该数据成员的声明中加mutable关键字
    };

    auto main() -> int {
        Screen screen;
        screen.display();
        screen.set("green screen").move(8,8).display();
        screen.move(6,6).set("red screen").display();
        //screen.display().set("error"); // [MinGW Makefiles] error: passing 'const test_starthis::Screen' as 'this' argument discards qualifiers [-fpermissive]
        
        return 0;
    }
}

输出:

contents_: my screen
x_: 0, y_: 0
The screen is displayed 1 times.
contents_: green screen
x_: 8, y_: 8
The screen is displayed 2 times.
contents_: red screen
x_: 6, y_: 6
The screen is displayed 3 times.

上述的操作screen.set("green screen").move(8,8).display();screen.move(6,6).set("red screen").display();都是在同一个对象上执行的。

如果令moveset返回Screen而非Screen&则上面两句的行为将大不相同。简单起见使用一个更简单的示例说明。

#include <iostream>
#include <string>

namespace test_starthis {
    
    class Screen{
    public:
        Screen() = default;
        Screen(int x, int y, std::string contents): x_(x), y_(y), contents_(contents), ct_(0){
            std::cout << "Screen ctor with parameter called." << std::endl;
        }
        
        // 类内实现,默认inline
        Screen set(std::string new_contents){
            contents_ = new_contents;
            
            return *this;
        }
        Screen move(int x, int y) {
            x_ = x;
            y_ = y;
            
            return *this;
        }
        
        // 从const函数返回的对象是const对象,因此返回值也需要加const
        const Screen& display() const {
            std::cout << "contents_: " << contents_ << std::endl;
            std::cout << "x_: " << x_ << ", y_: " << y_ << std::endl;
            
            ++ct_;  // 虽然函数是const,但由于ct_被mutable修饰了,因此可以修改ct_
            
            std::cout << "The screen is displayed " << ct_ << " times." << std::endl;
            
            return *this;   // *this是const对象
        }

    private:
        int x_ = 0;
        int y_{0};;
        std::string contents_{"my screen"};
        mutable unsigned int ct_{0};  // 如果想在const成员函数内修改类的某个数据成员,可在该数据成员的声明中加mutable关键字
    };

    auto main() -> int {
        Screen screen;
        screen.display();
        screen.move(6,6).set("red screen").display();
        screen.display();

        return 0;
    }
}

输出:

contents_: my screen
x_: 0, y_: 0
The screen is displayed 1 times.
contents_: red screen               // 这是函数返回值副本的内容
x_: 6, y_: 6                        // 这是函数返回值副本的左边
The screen is displayed 2 times.    // 这是函数返回值副本的display
contents_: my screen                // 从此处可以看出screen的内容并未改变
x_: 6, y_: 6
The screen is displayed 2 times.

本示例中screen.move(6,6).set("red screen").display();相当于:

Screen tmp1 = screen.move(6,6);
Screen tmp2 = tmp1.set("red screen");
tmp2 = tmp2.display();  // 因为display还是引用,因此此处没有副本产生

2.基于const的重载

#include <iostream>
#include <string>

namespace test_starthis {
    
    class Screen{
    public:
        Screen() = default;
        Screen(int x, int y, std::string contents): x_(x), y_(y), contents_(contents), ct_(0){
            std::cout << "Screen ctor with parameter called." << std::endl;
        }
        
        // 类内实现,默认inline
        Screen set(std::string new_contents){
            contents_ = new_contents;
            
            return *this;
        }
        Screen move(int x, int y) {
            x_ = x;
            y_ = y;
            
            return *this;
        }
        
        // 从const函数返回的对象是const对象,因此返回值也需要加const
        const Screen& display() const {
            std::cout << "const version -->\n";
            do_display();

            return *this;
        }

        Screen& display() {
            std::cout << "non-const version -->\n";
            do_display();
            
            return *this;
        }
        
        void do_display() const {
            std::cout << "contents_: " << contents_ << std::endl;
            std::cout << "x_: " << x_ << ", y_: " << y_ << std::endl;
            
            ++ct_;
            
            std::cout << "The screen is displayed " << ct_ << " times." << std::endl;           
        }

    private:
        int x_ = 0;
        int y_{0};;
        std::string contents_{"my screen"};
        mutable unsigned int ct_{0};  // 如果想在const成员函数内修改类的某个数据成员,可在该数据成员的声明中加mutable关键字
    };

    auto main() -> int {

        Screen screen1;
        screen1.display();                          // 调用非const版本
        const Screen screen2(6, 6, "red screen");
        screen2.display();                          // 调用const版本

        return 0;
    }
}

输出:

non-const version -->
contents_: my screen
x_: 0, y_: 0
The screen is displayed 1 times.
Screen ctor with parameter called.
const version -->
contents_: red screen
x_: 6, y_: 6
The screen is displayed 1 times.

3.类类型前向声明

#include <iostream>
#include <string>

namespace test_starthis {
    
    class Controller;
    
    class Screen{
    public:
        // Screen() = default; // 没有意义,因为有引用成员,必须在初始化列表中初始化
        Screen(Controller &controller): controller2_(controller){  // 此处Controller &controller不可改成Controller controller
            std::cout << "Screen ctor with parameter called." << std::endl;
        }
        
        void setController(Controller);  // forward declaration的incomplete type可用于函数参数
        Controller getController();      // 也可用于函数返回值

    private:
        //Controller controller_;  // error: field 'controller_' has incomplete type 'test_starthis::Controller'
        Controller* controller1_;   // [RIGHT],可使用指针形式
        Controller& controller2_;   // [RIGHT],可使用引用形式,但要注意构造函数中的入参也必须是引用,因为想要创建类的对象该类必须被定义过,前向声明不是定义
    };

    auto main() -> int {
        // 完成Controller的定义后
        // Controller controller;
        //Screen screen(controller);  

        return 0;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值