第十二章 类
code:
/* 第三部分 类和数据抽象 第12章 类 12.1 类的定义和声明 12.2 隐含的this指针 12.3 类作用域 12.4 构造函数 12.5 友元 12.6 static类成员 小结 第三部分 类和数据抽象 第12章 类 367 12.1 类的定义和声明 368 12.1.1 类定义:扼要重述 368 12.1.2 数据抽象和封装 369 12.1.3 关于类定义的更多内容 372 12.1.4 类声明与类定义 374 12.1.5 类对象 375 12.2 隐含的this指针 376 12.3 类作用域 380 类作用域中的名字查找 382 12.4 构造函数 385 12.4.1 构造函数初始化式 387 12.4.2 默认实参与构造函数 391 12.4.3 默认构造函数 392 12.4.4 隐式类类型转换 393 12.4.5 类成员的显式初始化 396 12.5 友元 396 12.6 static类成员 398 12.6.1 static成员函数 400 12.6.2 static数据成员 400 小结 403 术语 403 */ // 12.1 类的定义和声明 ------------------------------------------------------------------------------------------------- // in book #include <iostream> #include <sstream> #include <string> #include <vector> #include <list> #include <algorithm> #include <iterator> using namespace std; class Sales_item { public: // operations on Sales_item objects double avg_price()const; bool same_isbn(const Sales_item &rhs)const { return isbn == rhs.isbn; } // default constructor needed to initialize members of built-in type Sales_item(): units_sold(0), revenue(0.0){} // 构造函数初始化列表 private: std::string isbn; unsigned units_sold; double revenue; }; double Sales_item::avg_price()const { if(units_sold) return revenue / units_sold; else return 0; } int main() { return 0; } // test this #include <iostream> #include <sstream> #include <string> #include <vector> #include <list> #include <algorithm> #include <iterator> using namespace std; class Sales_item { public: // operations on Sales_item objects double avg_price() const; bool same_isbn(const Sales_item &rhs) const { return this->isbn == rhs.isbn; // } // default constructor needed to initialize members of built-in type Sales_item(): units_sold(0), revenue(0.0){} // 构造函数初始化列表 private: std::string isbn; unsigned units_sold; double revenue; }; double Sales_item::avg_price() const // const 成员函数不能改变其所操作的对象的数据成员 { if(this->units_sold) return this->threvenue / this->units_sold; // else return 0; } int main() { return 0; } #include <iostream> #include <string> using namespace std; class Screen { public: // interface member functions private: std::string contents; std::string::size_type cursor; std::string::size_type height, width; }; int main() { return 0; } // typedef #include <iostream> #include <string> using namespace std; class Screen { public: // interface member functions private: std::string contents; std::string::size_type cursor; std::string::size_type height, width; }; class Screen2 { public: // interface member functions typedef std::string::size_type index; private: std::string contents; index cursor; index height, width; }; int main() { return 0; } // 函数重载 #include <iostream> #include <string> using namespace std; class Screen { public: typedef std::string::size_type index; // return character at the cursor or at a given position char get()const { return contents[cursor]; } char get(index ht, index wd)const; // remaining members private: std::string contents; index cursor; index height, width; }; char Screen::get(index h, index w) const { return( 't' ); // just for test } int main() { Screen myscreen; char ch = myscreen.get(); // calls Screen::get() ch = myscreen.get(0, 0); // calls Screen::get(index, index) return 0; } // inline #include <iostream> #include <string> using namespace std; class Screen { public: typedef std::string::size_type index; // implicitly inline when defined inside the class declaration char get()const { return contents[cursor]; } // explicitly declared as inline; will be defined outside the class declaration inline char get(index ht, index wd)const; // inline not specified in class declaration, but can be defined inline later index get_cursor()const; private: std::string contents; index cursor; index height, width; }; // inline declared in the class declaration; no need to repeat on the definition char Screen::get(index r, index c)const { index row = r * width; // compute the row location return contents[row + c]; // offset by c to fetch specified character } // not declared as inline in the class declaration, but ok to make inline in definition inline Screen::index Screen::get_cursor()const // 定义类型的成员,如 Screen::index,使用作用域操作符来访问。 { return cursor; } int main() { class Screen myscreen; // class 经常不写 char ch = myscreen.get(); // calls Screen::get() ch = myscreen.get(0, 0); // calls Screen::get(index, index) return 0; } // 12.2 隐含的this指针 ------------------------------------------------------------------------------------------------- // this #include <iostream> #include <string> using namespace std; class Screen { public: typedef std::string::size_type index; // interface member functions Screen &move(index r, index c); Screen &set(char); Screen &set(index, index, char); // other members as before private: std::string contents; index cursor; index height, width; }; Screen &Screen::set(char c) { contents[cursor] = c; return *this; } Screen &Screen::move(index r, index c) { index row = r * width; // row location cursor = row + c; return *this; } int main() { class Screen myScreen; myScreen.move(4,0).set('#'); return 0; } // 基于 const 的重载 #include <iostream> #include <string> using namespace std; class Screen { public: typedef std::string::size_type index; // interface member functions Screen &move(index r, index c); Screen &set(char); Screen &set(index, index, char); //Screen(): height(0), width(0){} // 构造函数初始化列表 // //Screen( index i, index j ) { height=i; width=j; } // 加这两句 Screen(index i,index j):height(i),width(j){} // 也可以这样构造初始化列表 // display overloaded on whether the object is const or not Screen& display(std::ostream &os) { do_display(os); return *this; } const Screen& display(std::ostream &os) const { do_display(os); return *this; } private: void do_display(std::ostream &os) const { os << contents; } std::string contents; index cursor; index height, width; }; Screen &Screen::set(char c) { contents[cursor] = c; return *this; } Screen &Screen::move(index r, index c) { index row = r * width; // row location cursor = row + c; return *this; } int main() { Screen myScreen(5,3); const Screen blank(5, 3); myScreen.set('#').display(cout); // calls nonconst version blank.display(cout); // calls const version return 0; } // 可变数据成员 #include <iostream> #include <string> using namespace std; class Screen { public: typedef std::string::size_type index; Screen &move(index r, index c); Screen &set(char); Screen &set(index, index, char); Screen(index i,index j):height(i),width(j){} Screen& display(std::ostream &os) { do_display(os); return *this; } const Screen& display(std::ostream &os) const { do_display(os); return *this; } private: void do_display(std::ostream &os) const { ++access_ctr; // keep count of calls to any member function os << contents; } mutable size_t access_ctr; // 可变数据成员 may change in a const members std::string contents; index cursor; index height, width; }; Screen &Screen::set(char c) { contents[cursor] = c; return *this; } Screen &Screen::move(index r, index c) { index row = r * width; // row location cursor = row + c; return *this; } int main() { Screen myScreen(5,3); const Screen blank(5, 3); myScreen.set('#').display(cout); // calls nonconst version blank.display(cout); // calls const version return 0; } // 12.3 类作用域 ------------------------------------------------------------------------------------------------- #include <iostream> #include <string> using namespace std; class First { public: int memi; double memd; }; class Second { public: int memi; double memd; }; int main() { First obj1; // Second obj2 = obj1; // error: obj1 and obj2 have different types return 0; } #include <iostream> #include <string> using namespace std; class First { public: int memi; double memd; void tempf(){ cout << "test" << endl; } }; int main() { First obj; First *ptr = &obj; ptr->memi; obj.memi; ptr->tempf(); obj.tempf(); return 0; } // 类作用域中的名字查找 #include <iostream> #include <string> using namespace std; int i(43); class First { public: int memi; double memd; void tempf(){ cout << i << endl; } // 贯穿。全局变量一样贯穿进去 }; int main() { First obj; First *ptr = &obj; ptr->tempf(); obj.tempf(); return 0; } // 12.4 构造函数 ------------------------------------------------------------------------------------------------- // 实参决定使用哪个构造函数 #include <iostream> #include <string> using namespace std; class Sales_item { // other members as before public: // added constructors to initialize from a string or an istream Sales_item(const std::string &){cout << "string" << endl; }; Sales_item(std::istream &){cout << "istream" << endl; }; Sales_item(){ cout << "nothing" << endl; }; // just for test }; int main() { // uses the default constructor: // isbn is the empty string; units_soldand revenue are 0 Sales_item empty; // specifies an explicit isbn; units_soldand revenue are 0 Sales_item Primer_3rd_Ed("0-201-82470-1"); // reads values from the standard input into isbn, units_sold, and revenue Sales_item Primer_4th_ed(cin); return 0; } // 并非所有类成员都会默认初始化——内置类型的成员不进行隐式初始化 // **没有默认构造函数的类类型的成员,以及 const 或引用类型的成员,不管是哪种类型,都必须在构造函数初始化列表中进行初始化。** #include <iostream> #include <string> using namespace std; class First { public: int i; double d; string s; // 已经初始化为 empty tring }; int main() { First obj; First *ptr = &obj; cout << ptr->i << endl; // 基本数据类型没有初始化 cout << ptr->s << endl; cout << ptr->d << endl; return 0; } //下面的构造函数是错误的: #include <iostream> #include <string> using namespace std; class ConstRef { public: ConstRef(int ii); private: int i; const int ci; int &ri; }; // no explicit constructor initializer: error ri is uninitialized ConstRef::ConstRef(int ii) { // assignments: i = ii; // ok ci = ii; // error: cannot assign to a const ri = i; // assigns to ri which was not bound to an object } int main() { ConstRef refobj(42); return 0; } /* 记住,可以初始化 const 对象或引用类型的对象,但不能对它们赋值。在开始执行构造函数的函数体之前,要完成初始化。 初始化 const 或引用类型数据成员的唯一机会是构造函数初始化列表中。 必须对任何 const 或引用类型成员以及没有默认构造函数的类类型的任何成员使用初始化式。 */ #include <iostream> #include <string> using namespace std; class ConstRef { public: // ok: explicitly initialize reference and const members ConstRef::ConstRef(int ii): i(ii), ci(i), ri(ii) { } private: int i; const int ci; int &ri; }; int main() { ConstRef refobj(42); return 0; } /* 构造函数初始化列表仅指定用于初始化成员的值,并不指定这些初始化执行的次序。 成员被初始化的次序就是定义成员的次序。 所有会有警告:warning: 'X::j' will be initialized after 按照与成员声明一致的次序编写构造函数初始化列表是个好主意。此外,尽可能避免使用成员来初始化其他成员。 */ #include <iostream> #include <string> using namespace std; class X { int i; int j; public: // run-time error: i is initialized before j X(int val): j(val), i(j){} // 实际上是按定义的顺序。。即先i,再j }; int main() { X refobj(42); return 0; } // 12.5 友元 ------------------------------------------------------------------------------------------------- // 12.6 static类成员 ------------------------------------------------------------------------------------------------- // 书中只提供代码片断,要补全,比较坑爹。。总算编译成功。。 #include <iostream> #include <string> using namespace std; class Account { public: // interface functions here void applyint(){ amount += amount * interestRate; } static double rate() { return interestRate; } static void rate(double); // sets a new rate private: string owner; double amount; static double interestRate; static double initRate(); }; void Account::rate(double newRate) { interestRate = newRate; // sets a new rate } double Account::initRate() // for interestRate { return(3.14/100); } double Account::interestRate = initRate(); // only once int main() { Account ac1; Account *ac2 = &ac1; double rate; rate = ac1.rate(); // through an Account object or reference rate = ac2->rate(); // through a pointer to an Account object rate = Account::rate(); // directly from the class using the scope operator return 0; }