public public private protected private public private protected
� 承的方式 � 承方式 public 公有� 承 基� 成� 的�� 派生�� 基� 成� 的 �限 ��� 限 public private 不可� protected private 私有� 承 public private protected private 不可� private protected 保�� 承 public private protected 不可� protected 北京邮电大学 7
函数类型举例 class Shape { public: virtual void draw() const = 0; virtual void error(const string& msg); int object. ID() const; . . . }; Shape a; × class Rectangle: public Shape {. . . }; class Ellipse: public Shape {. . . }; 北京邮电大学 9
非虚函数不允许被覆盖 class B { public: virtual void mf 1(); void mf 2(); }; D x; B *p. B = &x; p. B->mf 1(); p. B->mf 2(); 禁止重新定义 class D: public B 非虚函数! D *p. D = &x; { public: virtual void mf 1(); void mf 2(); }; 北京邮电大学 p. D->mf 1(); p. D->mf 2(); 11
深入理解类之间的关系(4) o o 例子:正方形是一种特殊的矩形。 class Square : public Rectangle class Rectangle{ public: virtual void set. Height(int new. Height); virtual void set. Width(int new. Width); virtual int height( ) const; // 返回当前值 virtual int width( ) const; . . . }; void make. Bigger(Rectangle& r) { int old. Height = r. height(); r. set. Width(r. width() + 10); assert(r. height() == old. Height ); //判断r的高度是否未曾改变 } 15 北京邮电大学
深入理解类之间的关系(6) o 复合关系(composition) n has-a, is-implemented-in-terms-of class Person { … private: string name; string address; Phone. Number fixed. Number; Phone. Number mobile. Number; . . . }; 北京邮电大学 17
深入理解类之间的关系(8) class Set : public list { … }; ? class Set { public: bool member() const; void insert(. . . ); void remove(. . . ); . . . private: list items; }; 北京邮电大学 19
深入理解类之间的关系(9) class Person {. . . }; class Student : private person {. . . }; void eat (const Person& p); void study(const Student & s); Person p; Student s; eat(p); eat(s); 北京邮电大学 20
多态(1) class Shape { public: // 所有的形状都要提供一个函数绘制它们本身 virtual void draw() const = 0; }; class Rectangle: public Shape { public: virtual void draw() const; // 画矩形 Draw A }; class Circle: public Shape { public: virtual void draw() const; // 画圆形 Draw B }; 北京邮电大学 30
多态(2) ps动态类型:? // ps 静态类型 = Shape* Shape *ps; pc动态类型: // pc 静态类型 = Shape* Circle Shape *pc = new Circle; // pr 静态类型 = Shape* Shape *pr = new Rectangle; pr动态类型: Rectangle 北京邮电大学 31
动态绑定机制(2) 无虚函数的对象内存映像 o n sizeof(a) = sizeof(int) + sizeof(char); class A { } 对象a内存映像 int i; char j; func() {}; char j; 0 x 1234 Func() 对象b内存映像 a. func(); // CALL ABCD; int i; char j; b. func(); // CALL ABCD; 北京邮电大学 35
动态绑定机制(3) o 包含虚函数的对象内存映像 n func(): 0 x 1234 &A: : func 1: 0 x 2345 &A: : func 2: 0 x 3456 &B: : func 2: 0 x 4567 sizeof(a) = sizeof(int) + sizeof(char) + 4; class A { int i; char j; func() {}; virtual func 1() {}; virtual func 2() {}; }; class B : public class A { int k; virtual func 2() {}; }; 对象a内存映像 Class. A VTABLE vptr; &A: : func 1; int i; &A: : func 2; char j; 对象b内存映像 Class. B VTABLE vptr; &A: : func 1; int i; &B: : func 2; char j; 北京邮电大学 int k; 36
决不能把多态应用于数组(1) Tree的内存映像 0 i*sizeof(an class Tree {. . . }; object in the array, class Balanced. Tree : public Tree (. . . }; 1 就是Tree对象的大小) //输出树 void print. Tree. Array(const Tree array[], int number) { for ( int i = 0; i < number; i++) cout << array[i]; // *(array+i) } Tree tree. Array[10]; print. Tree. Array(tree. Array , 10); 2 3 Balanced. Tree 的内存映像 0 × 1 2 3 //指向父类的指针可以指向子类 Balanced. Tree b. Tree. Array[10]; print. Tree. Array(b. Tree. Array , 10); 北京邮电大学 38
构造函数(1) class Empty { }; class Empty { public: Empty() {}; Empty(const Empty& rhs) { }; ~Empty() {}; }; Empty& operator=(const Empty & rhs){ }; 北京邮电大学 41
构造函数(7) o class Singleton { 一个类仅有一个实例,并提供一个该实例的 全局访问点 private static Singleton *_instance=null; private Singleton(){ } public static Singleton get. Instance() { if(_instance == null) { o 提示:少使用全局变量 _instance = new Singleton(); } } } return *_instance; Singleton s = get. Instance(); 北京邮电大学 47
赋值和初始化(1) o o 赋值:assignment (=) 初始化:initialization Address. Entry(const string& name, const string& address, const list<Phonenumber>& phones) { _name = name; _address = address; _phones = phones; // 赋值 }; Address. Entry(const string& name, const string& address, const list<Phonenumber>& phones) : _name(name), _address(address), _phones(phones) { }; // 北京邮电大学 初始化 48
class Phonenumber {. . . }; class Address. Entry { public: Address. Entry(const string& name, const string& address, const list<Phonenumber>& phones); private: string _name; string _address; list<Phonenumber> _phones; . . . }; Address. Entry(const string& name, const string& address, const list<Phonenumber>& phones) { _name = name; _address = address; }; _phones = phones; . . . //这些都是赋值,而不是初始化! 北京邮电大学 49
Address. Entry(const string& name, const string& address, const list<Phonenumber>& phones) { _name = name; _address = address; _phones = phones; //这些都是赋值,而不是初始化!. . . }; Address. Entry(const string& name, const string& address, const list<Phonenumber>& phones) : _name(name), _address(address), _phones(phones) { }; 函数开销:_name的构造函数、_adddress的构造函数、 _phones的构造函数、Address. Entry的构造函数 北京邮电大学 51
赋值和初始化(4) o 尽可能延后变量定义式的出现时间 string encrypt. Password(const string & password) { string encrypted; if(password. length() < 20) return "password too short"; encrypted(password); return encrypted; }; string encrypt. Password(const string & password) { if(password. length() < 20) return "password too short"; string encrypted; encrypted(password); return encrypted; }; 北京邮电大学 53
赋值和初始化(5) o 尽可能延后变量定义式的出现时间 n n 延后变量的定义直到该变量必须被使用; 延后变量的定义直到能够获得该变量的初值。 string encrypt. Password(const string & password) { if(password. length() < 20) return "password too short"; string encrypted(password); return encrypted; }; 北京邮电大学 54
析构函数(1) class Timerkeeper{ public: Timekeeper() {}; ~Timekeeper() {}; … }; class Atomic. Clock: public Timerkeeper{…}; class Water. Clock: public Timerkeeper{…}; class Wrist. Clock: public Timerkeeper{…}; Timerkeeper *timer; timer = new Atomic. Clock; timer = new Water. Clock; … delete timer; 北京邮电大学 55
深入理解传值与传引用(1) o class person{ private: string name; string address; }; class student: public person{ private: string schoolname; string schooladdress; }; o o o bool validate. Student(student s){}; student a; bool s. Is. OK=validate. Student(a); 北京邮电大学 o student构造函数 1次 schoolname, schooladdress构造函数调 用各1次 person构造函数调用 1次 name,address构造函数 调用各1次 name,address析构函数 调用各1次 person析构函数调用 1次 schoolname, schooladdress析构函数调 用各1次 student析构函数 1次 57
深入理解传值与传引用(2) o bool validate. Student(student s){}; o bool validate. Student(const student &s){}; 北京邮电大学 58
深入理解传值与传引用(3) o 对象切割问题 class window{ public: string name() const; virtual void display() const; }; class window. With. Bar: public window{ public: virtual void display() const; }; void print. Name. And. Display(window w) { cout << w. name(); w. display(); }; window. With. Bar win; print. Name. And. Display(win); 北京邮电大学 59
深入理解传值与传引用(4) o void print. Name. And. Display(window w) o void print. Name. And. Display(const window& w) 北京邮电大学 60
深入理解传值与传引用(6) o 函数返回值传递引用 n 栈上内存(stack) n 堆上内存 class Rational{ private int n, d; public: const Rational& operator * ( const Rational& lhs, const Rational& rhs); . . . }; 北京邮电大学 62
深入理解传值与传引用(7) o 函数返回值传递引用 n 栈上内存(stack) n 堆上内存 Rational w, a, b, c; w = a * b * c; //申请的内存呢 const Rational& operator * ( const Rational& lhs, const Rational& rhs); { Rational result(lhs. n * rhs. n, lhs. d * rhs. d); return result; } const Rational& operator * ( const Rational& lhs, const Rational& rhs); { Rational *result = new Rational(lhs. n * rhs. n, lhs. d * rhs. d); return *result; } 北京邮电大学 63
自增运算符(++)和自减运算符(--) ++i; i++; // calls i. operator++() // calls i. operator++(0) Object i; o int参数 n 用作标志符 不给出参数 n //(i. operator++()). operator++() ++++ i; Object& Object: : operator++() o { //(i. operator++(0)). operator++(0) n 返回 引用 *this += 1; i++++; return *this; n 返回const对象 } const Object // Object: : operator++(int) i. operator++(0)的返回值是一个const o { //设为a,而a. operator++(0)是非法的! const Object old. Value = *this; n 至少减少四次 ++(*this); 函数调用 return old. Value ; } o 返回值 效率:使用前缀 一致性 北京邮电大学 65
- Slides: 66