(1)
If the pass-by-value parameter is passed when a function is called, the function parameters take the actual copy of the real parameter as the initial value, and the call end obtains a replica of the function return value.
See the following code:
class Person { public: Person(); virtual ~Person(); private: string name; string address; };class Student : public Person { public: Student(); ~Student(); private: string schoolName; string schoolAddress; };bool validateStudent(Student s); Student plato; bool platoIsOK = validateStudent(plato);
When the above function calls validateStudent (plato);, Student's copy constructor is called and s is initialized Based on plato. When validateStudent returns s, it is destroyed. Therefore, the parameter transfer cost is "one Student copy constructor call and one Student destructor call ".
But it is not the whole story. The Student object has two string objects, and the Student object inherits from the Person object. Therefore, the Person object must be constructed, and the Person object has two strings in it.
Therefore, passing a Student object in the by-value method will result in one Student copy constructor, one Person copy constructor, and four string copy constructor calls. When the Student replica is destroyed, each constructor action requires a corresponding destructor call action. Therefore, the overall cost is "Six constructor and six destructor "!
Solution: pass-by-reference-to-const
bool validateStudent(const Student& s);
In this way, no constructor or destructor is called because no new object is created. Const is necessary, and callers do not have to worry about validateStudent changing the Student they passed in.
(2)
By reference transmission parameters can also avoid slicing issues. When a derived class object is passed to a base class object by value. The copy constructor of base class is called, and the special properties of "constructing this object is like a derived class Object" are cut out, leaving only one base class object. This is because the base class constructor created it.
Assume that the following inheritance relationship exists:
class Window { public: string name() const; virtual void display() const; };class WindowWithScrollBars : public Window { public: virtual void display() const; };
Incorrect function Syntax:
void printNameAndDisplay(Window w) { std::cout << w.name(); w.display(); }
When calling the above function:
WindowWithScrollBars wwsb; printNameAndDisplay(wwsb);
W will be constructed into a Window object: pass-by-value, resulting in the removal of all the special information of wwsb "the reason why it is a wide wwithscrollbars object. Therefore, display always calls Window: display (). This is definitely not what we want !!!
Solution:
Transmit w by reference to const:
void printNameAndDisplay(const Window& w) { cout << w.name(); w.display(); }
Now, w shows the type of the input window.
(3)
Some compilers treat "built-in types" and "user-defined types" very differently, even though they have the same underlying representation. Some compilers will put a double variable into the cache, but will not put a class containing only one double into the cache.
When you look at the bottom layer of the c ++ compiler, you will find that the reference is often implemented by pointers. Therefore, the pass-by-reference usually means that the pointer is passed. Therefore, if you have an object of built-in type (such as int), pass by value is more efficient than pass by reference. This advice also applies to stl iterators and function objects, so they are traditionally designed as pass by values. Practitioners have the responsibility to see if they are efficient and not affected by cutting issues.
Remember:
(1) try to replace pass-by-reference-to-const with pass-by-value. The former is usually more efficient and can avoid the problem of cutting (slicing problem ).;
(2) The above rules are not suitable for built-in types, as well as STL iterators and function objects. For them, pass-by-value is often more suitable ..