dylanin1999

导航

Effective C++条款20:宁以pass-by-reference-to-const替换pass-by-value

条款20:宁以pass-by-reference-to-const替换pass-by-value

以下考虑类对象:

class Person
{
public:
    Person();
    virtual ~Person();
    //...

private:
    std::string name;
    std::string address;
};


class Student:public Person
{
public:
    Student();
    ~Student();
    //...

private:
    std::string schoolName;
    std::string schoolAddress;
};
    



//类的调用
bool validateStudent(Student s);
Student plato;
bool platoIsOK = validateStudent(plato);

上述类的调用中,在以传值得方式在进行参数传递,在上述使用中,由于是值传递,student 会进行拷贝构造,会调用一次Person和一次Student中的构造函数,由于string也是一个类,在student和person中各有两个string类,也就是说会调用四次string的构造函数,加起来一共会调用六次构造函数,同理,同时会调用六次析构函数。

 

当我们使用引用传参(pass-by-reference-to-const)

bool validateStudent(const Student& s);

这是,不会调用student的拷贝构造函数,也就不会有上述中的多次构造、析构函数的调用,这样就有效地提高了效率。

 

对象切割:当把一个派生类对象 pass-by-value  给一个基类对象时,会发生对象切割。

例子如下:

class Window
{
public:
    //...
    std::string name() const;
    virtual void display() const;
};

class WindowWithScrollBars:public Window
{
public:
    //...
    virtual void display() const;
}
void printNameAndDisplay(Window w)
{
    std::cout<<w.name();
    w.display();
}

//调用函数
WindowWithScrollBars wwsb;
printNameAndDisplay(wwsb);

printNameAndDisplay() 函数中,我们pass-by-value时,对象就可能会被切割,函数会将其视为一个Window对象,而不是WindowWithScrollBars 对象,它所有作为WindowWithScrollBars 对象的特性都会被切除(忽视),这就是对象切割。

但是通过pass-by-reference-to-const就可以很有效地解决问题。

代码如下:

void printNameAndDisplay(const Window& w)
{
    std::cout<<w.name();
    w.display();
}

//调用函数
WindowWithScrollBars wwsb;
printNameAndDisplay(wwsb);

但是,当对象属于内置类型时,pass-by-value通常比pass-by-reference-to-const的效率要高,STL的迭代器和函数对象,都使用了pass-by-value.

 

要记住的点:

1、尽量以pass-by-reference-to-const替换pass-by-value。通常前者比较高效,并可避免对象的切割问题(slicing problem)

2、以上规则并不适用于内置类型,以及STL的迭代器和函数对象。对他们而言,pass-by-value往往比较适当

posted on 2022-08-13 16:15  DylanYeung  阅读(26)  评论(0编辑  收藏  举报