C++ 类 超细节攻略
C++坑了我不少的时间,这回把类算是弄得明白一些,在此记录一下。内容非常繁杂,请做好心理准备。
我会以代码的形式来表达,并且附上一些解释。
① 编译器分两步处理类:
- 编译成员的声明
- 直到类全部可见后才编译成员函数体
② C++ 中class与struct的区别?
- C++中唯一区别就是默认的访问权限,struct是public,class是private
- C#中区别很大,详情百度
③ .h文件 (注意:是struct)
1 struct Sales_data 2 { 3 // 定义友元函数让其可以访问类的非公有成员 4 friend Sales_data add(const Sales_data &, const Sales_data &); 5 6 public: 7 // Sales_data() = default; 8 // 构造函数,不能声明const 9 // 等同于编译器自动合成的构造函数 10 // 在(= default)在类的内部,则默认构造函数是内联的,如在类的外部,则该成员默认不是内联的 11 12 Sales_data() : Sales_data("", 0, 0) {} 13 // 委托构造函数:使用它所属的类的其他构造函数执行自己的初始化过程 14 15 /* explicit 抑制构造函数的隐式转换,只允许出现的类内*/ Sales_data(const string &s) : bookNo(s) {} 16 Sales_data(const string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p*n) {} 17 18 string isbn() const {return bookNo;} 19 // 等价于 20 // string isbn(const Sales_data *const this//隐式//) {return this->bookNo;} 21 // 意思就是this是一个指向常量的常量指针。不能修改this中的内容。 22 23 Sales_data& combine (const Sales_data&); 24 25 26 private: 27 double avg_price() const; 28 string bookNo; 29 unsigned units_sold = 0; 30 double revenue = 0.0; 31 };
④ .cpp文件
1 Sales_data& Sales_data::combine(const Sales_data &rhs) 2 { 3 units_sold += this->units_sold; 4 revenue += rhs.revenue; 5 return *this; // 返回指针引用 6 } 7 8 double Sales_data::avg_price() const 9 { 10 if (units_sold) 11 return revenue / units_sold; 12 else 13 return 0; 14 } 15 16 Sales_data add(const Sales_data &lhs, const Sales_data &rhs) 17 { 18 Sales_data sum = lhs; 19 sum.combine(rhs); 20 return sum; 21 }
⑤ main函数
1 int main() 2 { 3 Sales_data total; 4 total.isbn(); 5 // 等价于 6 // total.isbn(&total); 7 // 调用时候传入了total对象的地址 8 9 const Sales_data sales_data; 10 // 直到构造函数完成初始化过程,对象才能真正取得其“常量”属性 11 // 构造函数在const对象的构造过程中可以向其写值 12 13 total.combine(sales_data).isbn(); 14 // 非引用传参调用拷贝构造(此函数是引用参数,则没有拷贝构造) 15 // 返回一个类对象调用拷贝构造 16 17 total = sales_data; 18 // 赋值操作 19 20 Sales_data obj(); // 声明了一个函数 21 Sales_data obj2; // 声明了一个对象 22 23 Sales_data item; 24 string null_book = "9-999-99999-9"; 25 item.combine(null_book); // 将null-book隐式转换成Sales_data对象 26 //item.combine("9-999-99999-9"); // 错误,只允许一步转换,不能将字符转换成string再转换成对象 27 28 // this 是一个常量指针 29 return 0; 30 }
⑥ class Screen 与⑦的类示例友元类
1 class Screen 2 { 3 public: 4 typedef std::string::size_type pos; 5 // 等同于 6 // using pos = std::string::size_type; 7 // 必须先定义后使用 8 9 friend class Window_mgr; 10 // Window_mgr的成员可以访问Screen类的私有成员 11 12 // friend void Window_mgr::clear(ScreenIndex); 13 // 让函数作为友元 14 15 Screen() = default; 16 Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c) {} 17 18 char get() const // 隐式内联 19 { 20 return contents[cursor]; 21 } 22 23 inline char get(pos ht, pos wd) const; // 显式内联 24 25 Screen &move(pos r, pos c); // 可以在类的外部声明时定义成内联函数 26 27 Screen &set(char); 28 29 Screen &set(pos, pos, char); 30 31 const Screen &display() const; 32 33 void dummy_fcn(pos height) 34 { 35 cursor = width * height; // 用的是参数height 36 cursor = width * this->height; // 用的是成员height 37 // cursor = width * ::height; // 用的是全局的height 38 } 39 40 private: 41 pos cursor = 0; 42 pos height = 0, width = 0; 43 std::string contents; 44 mutable size_t access_ctr = 0; // mutable(可变数据成员),在const成员函数中也可以改变值 45 }; 46 47 char Screen::get(pos ht, pos wd) const 48 { 49 pos row = ht * width; 50 ++access_ctr; // 正确 51 // ++cursor; 错误 52 return contents[row + wd]; 53 } 54 55 inline Screen &Screen::move(pos r, pos c) // 声明的时候声明inline函数 56 { 57 pos row = r * width; 58 cursor = row + c; 59 return *this; 60 } 61 62 inline Screen &Screen::set(char c) 63 { 64 contents[cursor] = c; 65 return *this; 66 // 返回对象的引用,说明返回的是对象本身,而不是对象的拷贝 67 // 如果返回类型为Screen,则返回的是对象的拷贝 68 } 69 70 inline Screen &Screen::set(pos r, pos col, char ch) 71 { 72 contents[r * width + col] = ch; 73 return *this; 74 } 75 76 inline const Screen &Screen::display() const 77 { 78 return *this; // const成员函数返回其指针,则为常量指针 79 }
⑦ class Window_mgr
1 class Window_mgr 2 { 3 public: 4 using ScreenIndex = std::vector<Screen>::size_type; 5 6 void Clear(ScreenIndex); 7 8 ScreenIndex addScreen(const Screen&); 9 10 private: 11 std::vector<Screen> screens{ Screen(24, 80, ' ') }; 12 // 类内初始值,必须以符号=或{}表示 13 }; 14 15 void Window_mgr::Clear(ScreenIndex index) // void 为作用域之外,从Window_mgr开始为作用域内 16 { 17 Screen &s = screens[index]; 18 s.contents = std::string(s.height * s.width, ' '); 19 // 因Window_mgr是Screen的友元类,所以可以访问Screen的私有成员height、width和contents 20 // 注:友元关系不存在传递性,如果Window_mgr有友元类,其友元类没有访问Screen的权利 21 } 22 23 Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen &s) // 返回类型在类作用域中定义,则必须用类名 24 { 25 screens.push_back(s); 26 return screens.size() - 1; 27 }
如有补充欢迎留言~