条款20:宁以 pass-by-reference-to-const 替换 pass -by -value
1:采用后者效率高;看代码:
#include <iostream> using namespace std; class Person { public: Person() { cout<<"Person()"<<endl; } Person(const Person& p) { cout<<"Person(const Person& p)"<<endl; } virtual ~Person() { cout<<"~Person()"<<endl; } private: string name; string address; }; class Student:public Person { public: Student() { cout<<"Student()"<<endl; } Student(const Student& p) { cout<<"Student(const Student& p)"<<endl; } virtual ~Student() { cout<<"~Student()"<<endl; } private: string schoolName; string schoolAddress; }; void Print(Student s) { } int main() { Student stu; Print(stu); return 0; } /* Student stu; Print(stu); 当调用上面的函数时,Student的copy构造函数会被调用,以stu为蓝本讲s初始化,函数结束时, s会被销毁,因此参数的传递成本是 一次Student copy构造函数调用,加上一次student析构函数调用 Person 有两个String 对象 Student 有两个String对象 所以上面参数的传递成本要加上 4个String的构造函数与析构函数 同样,一次Student构造函数调用,必然Person的构造函数调用 这样下来,上面传递的成本总共是: 六次构造函数和六次析构函数 effective C++ 条款20 当中说 这里会 调用 Student的 copy 构造函数 和 Person的 copy构造函数,我这里实验 调用Student的copy 构造函数,但是不会调用Person的 copy 构造函数; 这个我单独编写了一个程序证明我的是对的,调用的是子类的copy构造函数,不会调用父类的copy构造函数。 综上来说,这么传递的效率太低。 */
这个我单独编写了一个程序证明我的是对的,调用的是子类的copy构造函数,不会调用父类的copy构造函数。
看代码:
#include <iostream> using namespace std; class Parent { public: Parent() { cout<<"调用父类的无参构造函数"<<endl; } Parent(const Parent& p) { cout<<"父类的copy 构造函数"<<endl; } ~Parent() { } }; class Children:public Parent { public: Children() { cout<<"调用子类的无参构造函数"<<endl; } Children(const Children& c) { cout<<"子类的copy 构造函数"<<endl; } ~Children() { } }; int main() { Children aa; Children bb(aa); /* 调用父类的无参构造函数 调用子类的无参构造函数 调用父类的无参构造函数 子类的copy 构造函数 */ return 0; }
上面代码说明了 子类对象调用copy构造函数构造对象的时候,不会调用父类的copy构造函数,而是调用的父类的普通构造函数。
2:后者避免对象切割问题;看代码:
#include <iostream> using namespace std; class Base { public: Base() { cout<<"调用父类的构造函数"<<endl; } Base(const Base& b) { cout<<"调用的是父类的copy 构造函数"<<endl; } ~Base() { } virtual void display() const { cout<<"调用的是父类的display函数"<<endl; } private: int i; }; class Derived : public Base { public: Derived() { cout<<"调用子类的构造函数"<<endl; } ~Derived() { } virtual void display() const { cout<<"调用的是子类的display函数"<<endl; } }; void print(Base b) { b.display();//参数被切割 即使传递子类对象,调用的也是父类的display函数 } void print2(const Base& b) { b.display(); } int main() { Derived aa; print(aa); //这里调用了 父类的copy构造函数 父类的print函数; print2(aa); return 0; } /* 以值传递的方式传递 上面说的一个缺点是:效率低下 下面再说另外一个缺点:对象切割问题 void print(Base b) { b.display();//参数被切割 调用的是父类的函数 } Derived aa; print(aa); aa为子类,Print的参数为基类 当一个子类的对象以值传递方式传递并被视为一个基类对象,基类的copy 构造函数会被调用,而“造成此对象的行为像个子类对象”的 那些特化性质完全被切割掉了,仅仅留下以一个基类对象。发生了参数切割。 采用引用传值可以解决这个问题。 */
所以 以值传递方式 子类赋给父类的时候会发生对象切割,采用引用代替他。
总结一句话:
尽量以pass-by-reference-to-const 替换 pass -by -value;前者通常比较高效,并可以避免切割问题。
时间: 2024-10-03 14:55:49