C++学习之路: class的this隐式指针讨论
class内部的成员函数是不需要把 自己的 privata元素传入的。因为系统已经通过this指针帮我们传入了。
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 using namespace std; 5 6 /* 7 * 本例错误的原因是:set系列函数返回的是对象 8 * 所以返回时产生了一个临时的对象 9 */ 10 class Student 11 { 12 public: 13 Student() 14 :id_(0), name_(""), age_(0) 15 { 16 cout << "构造Student" << endl; 17 } 18 19 ~Student() 20 { 21 cout << "销毁Student" << endl; 22 } 23 24 25 Student setId(int id) 26 { 27 id_ = id; 28 return *this; 29 } 30 31 Student setName(const string name) 32 { 33 name_ = name; 34 return *this; 35 } 36 37 Student setAge(int age) 38 { 39 age_ = age; 40 return *this; 41 } 42 43 void print(ostream &os) const 44 { 45 os << id_ << " " << name_ << " " << age_ << endl; 46 } 47 48 private: 49 int id_; 50 string name_; 51 int age_; 52 }; 53 54 55 int main(int argc, const char *argv[]) 56 { 57 Student s; 58 s.setId(11).setName("zhangsan").setAge(88).print(cout); //此处通过值拷贝返回了3个局部对象 {id_= 0, Name_ = "", age_ = 0} 59 s.print(cout); //传入给setId() 返回一个拷贝 ①{id_= 11, Name_ = "", age_ = 0} 60 //传入给setName() 值拷贝返回一个局部对象②{id_= 11, Name_ = "zhangsan", age_ = 0} 61 //传入给setAge() 值拷贝返回一个局部对象③{id_= 11, Name_ = "zhangsan", age_ = 88} 62 63 return 0; }
构造Student 11 zhangsan 88 销毁Student 销毁Student 销毁Student 11 0 销毁Student //结果打印了销毁了3个局部变量
综上,如果不通过返回引用的方式return s,成员函数其实返回的是一个拷贝的副本, 上面我们已经分析过了一共调用了3次成员函数,共返回了3个局部对象,
分别是:
①{id_= 11, Name_ = "", age_ = 0} 是由setId()返回的一个副本
②{id_= 11, Name_ = "zhangsan", age_ = 0} 由setName()返回的一个副本
③{id_= 11, Name_ = "zhangsan", age_ = 88} 有setAge()返回的一个副本
##(参考《C与指针》)它们的作用域,是相继屏蔽的。作用域的知识可以参考c与指针
下面我们尝试使用返回引用的方式,让对象的成员函数返回自身的引用 的正确做法。
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 using namespace std; 5 6 /* 7 * 本例演示了,this返回自身引用的正确做法 8 * 9 * 同时说明了重载print函数const版本的必要性 10 */ 11 class Student 12 { 13 public: 14 Student() 15 :id_(0), name_(""), age_(0) 16 { 17 cout << "构造Student" << endl; 18 } 19 20 ~Student() 21 { 22 cout << "销毁Student" << endl; 23 } 24 25 26 Student &setId(int id) 27 { 28 id_ = id; 29 return *this; 30 } 31 32 Student &setName(const string name) 33 { 34 name_ = name; 35 return *this; 36 } 37 38 Student &setAge(int age) 39 { 40 age_ = age; 41 return *this; 42 } 43 44 const Student &print(ostream &os) const //这一行,如果函数时const版本,那么返回值也必须是const 否则在语义上造成歧义, 编译器会报错 45 { 46 os << id_ << " " << name_ << " " << age_ << endl; 47 return *this; 48 } 49 50 Student &print(ostream &os) //此处重载了一个非const版本用于重载 51 { 52 os << id_ << " " << name_ << " " << age_ << endl; 53 return *this; 54 } 55 56 private: 57 int id_; 58 string name_; 59 int age_; 60 }; 61 62 63 int main(int argc, const char *argv[]) 64 { 65 Student s; 66 s.setId(11).print(cout).setName("zhangsan").setAge(88).print(cout); 67 s.print(cout); 68 return 0; 69 }
上述代码我们演示了返回自身引用的 正确做法, 然而 在print打印函数,我们又重载了一个非const的版本,为什么要这么做呢?
我们知道, 当我们使用对象成员函数时, 如果传入的是一个const常量,那么该常量只能调用cons版本的函数进行处理,
输入非常量时,则调用const 和 非const 版本都可以,
const 的返回值依然还是const,有时我们不希望它返回一个const常量,而是希望返回一个变量 使得我们可以改变它,
由此我们重载了一个非const版本。