类
一.类成员函数的定义方法
1.在类声明中声明,类声明外定义
1 #include<iostream> 2 using namespace std; 3 4 class Person 5 { 6 public: 7 void setAge(unsigned n); 8 unsigned getAge() const; 9 private: 10 unsigned age; 11 }; 12 13 void Person::setAge(unsigned n) 14 { 15 age = n; 16 } 17 18 unsigned Person::getAge() const 19 { 20 return age; 21 } 22 23 int main() 24 { 25 return 0; 26 }
2.在类声明中声明和定义
1 #include<iostream> 2 using namespace std; 3 4 class Person 5 { 6 public: 7 void setAge(unsigned n) 8 { 9 age = n; 10 } 11 12 unsigned getAge() const 13 { 14 return age; 15 } 16 private: 17 unsigned age; 18 }; 19 20 int main() 21 { 22 return 0; 23 }
二.类声明通常放到.h文件中,不要将成员函数的定义放到.h中
三.一般来说应该采用引用的方式进行对象的传递和返回,而不要采用传值。传递一个指向对象的指针和引用方式效果相同,但引用语法简练。
四.const用法
const成员函数仅能调用其它const成员函数,非const成员函数可能会间接地改变对象状态
1.重载,2个成员函数(函数名,参数列表)一致,但一个有const一个无
不算重名,算重载
常对象调用常函数,非常对象调用非常函数
1 #include<iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 A() 8 { 9 x = 5; 10 } 11 int getValue() 12 { 13 return x; 14 } 15 16 int getValue() const 17 { 18 return 2 * x; 19 } 20 private: 21 unsigned x; 22 }; 23 24 int main() 25 { 26 A a1; 27 const A a2; 28 cout << a1.getValue() << endl; // 5 29 cout << a2.getValue() << endl; // 10 30 return 0; 31 }
2.三种const
1 #include<iostream> 2 using namespace std; 3 4 class C 5 { 6 public: 7 void set(const int n)//set不会改变n 8 { 9 x = n; 10 } 11 12 const int& get() const//第一个const:get会返回一个const型引用,谁也不能通过这个引用修改x,不能修改返回值 13 { //第二个const:get不会改变C中的数据成员 14 return x; 15 } 16 private: 17 int x 18 }; 19 20 int main() 21 { 22 return 0; 23 }
若函数采用const返回,则返回值只赋给一个const类型局部变量;
const返回值是一个类的指针或者引用的话,则不能用该指针或者引用调用该类的non-const成员函数,因为这些函数可能会改变该类数据成员;
常量对象不能执行非常量成员函数。
1 #include<iostream> 2 using namespace std; 3 4 class C 5 { 6 public: 7 int &f1() 8 { 9 mszt = 5; 10 return mszt; // 可修改mstz,可修改返回值 11 } 12 13 int &f2() const 14 { 15 return a; // error,无法将const int转换为int&,去掉& 16 } 17 18 const int& f3() 19 { 20 a = 5; 21 return a; //可修改a,不可修改返回值 22 } 23 24 void PrintMszt() 25 { 26 cout << mszt << endl; 27 } 28 29 void PrintA() 30 { 31 cout << a << endl; 32 } 33 private: 34 int mszt, a; 35 }; 36 37 int main() 38 { 39 C c; 40 int &s = c.f3(); // error,s不是const 41 const int& s1 = c.f3(); //ok 42 cout << s1 << endl; 43 s1 = 20;//error 44 return 0; 45 }
3.对const成员不能直接赋值
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class C 6 { 7 public: 8 C():c(0)//要用初始化列表 9 { 10 x = -1; 11 } 12 13 private: 14 const int c; 15 int x; 16 }; 17 18 int main() 19 { 20 return 0; 21 }
五.构造函数
1.构造函数无返回类型,与类同名;
2.创建一个对象时,构造函数会被编译器自动调用;
3.希望只使用带参构造函数时,提供公有带参构造函数,而不提供默认构造函数,或者提供私有的默认构造函数
1 #include<iostream> 2 using namespace std; 3 4 class C 5 { 6 public: 7 C(int a) {} 8 private: 9 C() {} 10 }; 11 12 int main() 13 { 14 C c;//error 15 C c(1);//OK 16 return 0; 17 }
六.拷贝构造
Person(Person&); Person(const Person&);
拷贝构造函数可以有多于一个的参数,但第一个以后的所有参数都必须有默认值
Person(const Person& p, bool married = false);
若一个类包含指向动态存储空间指针类型的数据成员,应为这个类设计拷构。否则:
1 #include<iostream> 2 using namespace std; 3 4 class P 5 { 6 public: 7 P(); 8 P(const string[], int); 9 void set(const string[], int); 10 private: 11 int size; 12 string *p; 13 }; 14 15 int main() 16 { 17 string list[10]; 18 P p1(list, 3); 19 P p2(p1);//默认拷构 20 return 0; 21 }
p1.p和p2.p指向同一块存储空间,潜在p1的操作会改变p2,且调用析构时会对同一值析构两次。
1 #include<iostream> 2 using namespace std; 3 4 class C 5 { 6 public: 7 C() 8 { 9 cout << "Default" << endl; 10 num = 0; 11 } 12 13 C(const C &c) 14 { 15 cout << "Copy" << endl; 16 //num = c.num;若有,若无 17 } 18 19 void set(int n) 20 { 21 num = n; 22 } 23 24 int get() const 25 { 26 return num; 27 } 28 private: 29 int num; 30 }; 31 32 void f(C c4)//copy 33 { 34 cout << "enter f(c)" << '\t'; 35 c4.set(-999); 36 cout << "c4:" << c4.get() << '\t' << "leaving f(c)" << endl; 37 } 38 39 C g() 40 { 41 cout << "enter g()" << endl; 42 C c3;//default 43 cout << "c3:" << c3.get() << '\n'; 44 c3.set(123); 45 cout << "c3:" << c3.get() << '\t' << "leaving g()" << endl; 46 return c3;//copy 47 } 48 49 int main() 50 { 51 C c1, c2;//default 52 cout << "c1:" << c1.get() << '\t'; 53 cout << "c2:" << c2.get() << endl; 54 f(c1); 55 cout << "c1:" << c1.get() << endl; 56 c2 = g(); 57 cout << "c2:" << c2.get() << endl;//若有123,若无乱码 58 return 0; 59 }
用一个已存在的对象去构造一个不存在的对象(构造之前不存在)就是拷贝构造。用一个已存在的对象去覆盖另一个已存在的对象,就是赋值运算。
若对象很大,进行对象间的拷贝的话,非常费空间和时间,改进:
把拷贝构造设计成私有成员;
把void f(C c)=> void f(C &c),C g()=>C &g()
七.转型构造函数(单参数构造函数)
1 #include<iostream> 2 using namespace std; 3 4 class Complex 5 { 6 public: 7 Complex(int i) 8 { 9 cout << "Int Constructor" << endl; 10 real = i, imag = 0; 11 } 12 13 Complex(double r, double i) 14 { 15 cout << "Double Constructor" << endl; 16 real = r, imag = i; 17 } 18 19 Complex(Complex &c) 20 { 21 cout << "Copy Constructor" << endl; 22 real = c.real; 23 imag = c.imag; 24 } 25 26 int real, imag; 27 }; 28 29 int main() 30 { 31 Complex c1(7, 8);//Double Constructor 32 Complex c2 = 12;//Int Constructor 33 c1 = 9;//Int Constructor, 9隐式类型转换 34 cout << c1.real << " " << c2.imag << endl;//9 0 35 Complex c3 = c1;//Copy Constructor 36 return 0; 37 }
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Person 6 { 7 public: 8 Person() 9 { 10 name = "Unknown"; 11 } 12 13 Person(const string &n)//转型构造 14 { 15 cout << "转型" << endl; 16 name = n; 17 } 18 19 Person(const char *n)//转型构造 20 { 21 cout << "转型" << endl; 22 name = n; 23 } 24 25 Person(Person &p)//转型构造 26 { 27 cout << "Copy" << endl; 28 name = p.name; 29 } 30 31 string name; 32 }; 33 34 void f(Person p) 35 { 36 cout << 1 << endl; 37 } 38 39 int main() 40 { 41 Person s1("Dave"); 42 Person s2("Ben"); 43 string str = "Peter"; 44 f(str);//显示“转型”,不显示“转型”,在构造时,调用了转型构造函数 45 s1 = str;//str转型为Person类型,显示“转型” 46 s1 = s2;//什么都不显示,不存在Copy和转型 47 return 0; 48 }
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Person 6 { 7 public: 8 Person() 9 { 10 name = "Unknown"; 11 } 12 13 explicit Person(const string &n)//在转型构造函数前加上explicit,关闭隐式类型转换 14 { 15 name = n; 16 } 17 private: 18 string name; 19 }; 20 21 int main() 22 { 23 Person p("Dave"); 24 string b = "bar"; 25 p = b;//error 26 return 0; 27 }
八.析构函数
析构函数没有参数和返回值,一个类最多一个析构函数
定义类时没写析构函数,则编译器生成缺省析构函数,不涉及释放用户申请的内存释放等清理工作。
1 #include<iostream> 2 using namespace std; 3 4 class C 5 { 6 public: 7 C() 8 { 9 cout << "Construct" << endl; 10 } 11 ~C() 12 { 13 cout << "Destructor" << endl; 14 } 15 }; 16 17 int main() 18 { 19 C c1[2], *c2 = new C[3]; 20 return 0; 21 } 22 /* 23 Construct 24 Construct 25 Construct 26 Construct 27 Construct 28 Destructor 29 Destructor 30 */
1 #include<iostream> 2 using namespace std; 3 4 class C 5 { 6 public: 7 C() 8 { 9 cout << "Construct" << endl; 10 } 11 ~C() 12 { 13 cout << "Destructor" << endl; 14 } 15 }; 16 17 int main() 18 { 19 C *c2 = new C[3]; 20 delete[] c2; 21 return 0; 22 } 23 /* 24 Construct 25 Construct 26 Construct 27 Destructor 28 Destructor 29 Destructor 30 */