圖形
矩形、正方形、圓形
計算面積、面積輸出
·面向對象設計,類?
·實現功能?
·運行時多態性測試?
1 #include <iostream>
2 using namespace std;
3
4 class Shape
5 {
6 protected:
7 double area;
8 public:
9 virtual double getArea() const = 0;
10 virtual void showArea()
11 {
12 cout << area << endl;
13 }
14 // friend ostream& operator << (ostream& out, const Shape& s);
15 };
16
17 ostream& operator << (ostream& out, const Shape& s)
18 {
19 out << s.getArea();
20 return out;
21 }
22
23 class Rectangle : public Shape
24 {
25 private:
26 double x;
27 double y;
28 public:
29 Rectangle(double i = 0.0, double j = 0.0) : x(i), y(j)
30 {
31 area = x * y;
32 }
33 virtual double getArea() const
34 {
35 return area;
36 }
37 };
38
39 class Square : public Shape
40 {
41 private:
42 double x;
43 public:
44 Square(double i = 0.0) : x(i)
45 {
46 area = x * x;
47 }
48 virtual double getArea() const
49 {
50 return area;
51 }
52 };
53
54 class Circle : public Shape
55 {
56 private:
57 double r;
58 static const double PI;
59 public:
60 Circle(double i = 0.0) : r(i)
61 {
62 area = PI * r * r;
63 }
64 virtual double getArea() const
65 {
66 return area;
67 }
68 };
69
70 const double Circle::PI = 3.1415926;
71
72 int main()
73 {
74 Shape* p;
75 p = new Rectangle(4, 5);
76 cout << p->getArea() << endl;
77 p->showArea();
78 delete p;
79 p = new Square(5);
80 cout << p->getArea() << endl;
81 p->showArea();
82 delete p;
83 p = new Circle(5);
84 cout << p->getArea() << endl;
85 p->showArea();
86 delete p;
87
88
89 Rectangle r(6, 7);
90 Square s(7);
91 Circle c(9);
92 cout << r << endl;
93 cout << s << endl;
94 cout << c << endl;
95
96 return 0;
97 }
posted @
2011-06-16 11:46 unixfy 閱讀(203) |
評論 (0) |
編輯 收藏
賦值運算符的重載,有不同的方法,Effective C++ 中有一個條款對此介紹。
1 #include <iostream>
2 using namespace std;
3
4 class MyString
5 {
6 private:
7 unsigned len;
8 char* data;
9 public:
10 MyString(const char* s = "");
11 MyString(const MyString& s);
12 MyString& operator = (const MyString& s);
13 ~MyString();
14 };
15
16 MyString::MyString(const char* s)
17 {
18 len = strlen(s);
19 data = new char[len + 1];
20 if (data != 0)
21 {
22 strcpy(data, s);
23 }
24 }
25
26 MyString::MyString(const MyString& s)
27 {
28 len = s.len;
29 data = new char[len + 1];
30 if (data != 0)
31 {
32 strcpy(data, s.data);
33 }
34 }
35
36 MyString& MyString:: operator = (const MyString& s)
37 {
38 // 第一種方法,需要檢測自賦值,因為如果不檢測,則會造成當自賦值時,就直接將該對象的 data delete 了,也就是 s.data 被 delete 了。這時 s.data 是個懸置指針,所致內存極可能無效
39 //
40 //if (this != &s)
41 //{
42 // delete [] data;
43 // len = s.len;
44 // data = new char[len + 1];
45 // if (data != 0)
46 // {
47 // strcpy(data, s.data);
48 // }
49 //}
50 //return *this;
51
52 // 另一種方法, 不需要檢測自賦值
53 // 這種方式需要做一個備份,自賦值情況下,temp 保持了另一份備份,即便 delete 了 data 還是留有一份
54 // 非自賦值的情況下,對 s.data 所指的內容有了一個備份,然后 delete data,將 temp 賦予 data,這樣有了兩份 s.data,到達賦值的目的
55 len = s.len;
56 char* temp = new char[len + 1];
57 if (temp != 0)
58 {
59 strcpy(temp, s.data);
60 }
61 delete [] data;
62 data = temp;
63 return *this;
64
65 // 兩種方法的代價分析
66 // 第一種方法,需要每次都要檢測是不是自賦值了,對于自賦值的情況,雖然檢測了,但是避免了備份,有利于自賦值的情況。但是對于非自賦值的情況,都需要額外的檢測,這種檢測是浪費的
67 // 第二種方法,不管是自賦值還是非自賦值都需要備份,這種方法對于自賦值的情況,較第一種方法代價高些,但是對于非自賦值的情況它不需要檢測,也是做一個 copy 所以非自賦值的情況效率由于第一種方法
68 // 也就是說第一種方法對于自賦值的情況好,第二種方法對于非自賦值的情況好。一般情況下,自賦值的情況并不經常出現,所以第一種檢測自賦值的操作很多情況下是多余的,所以相對第一種方法,第二種方法更好些。
69 }
70
71 MyString::~MyString()
72 {
73 len = 0;
74 delete [] data;
75 }
76
77 int main()
78 {
79 MyString a("C++ Programming"), c("Hello");
80 MyString b(a);
81 c = b;
82 cout << ". . ." << endl;
83 return 0;
84 }
posted @
2011-06-16 10:56 unixfy 閱讀(244) |
評論 (0) |
編輯 收藏
Function 語意學
static member functions 不可能做的
·存取 nonstatic 數據
·被聲明為 const
·virtual
·volatile
this
·T* const this
·const T* const this
名字的特殊處理 name mangling
名字_類名_參數鏈表
((Point3d*)0)->object_count();
virtual member functions
虛擬成員函數
任何問題都可以通過添加一個中間層來解決,實現多態就是通過添加了一個虛函數表和虛函數表指針這個中間層實現的
多重繼承下的 virtual functions
thunk
address points
virtual base class
不要聲明 nonstatic data member
構造函數的調用
指向 member function 的指針
double (Point::*pmf)();
指向 virtual member functions 的指針
ptr->z()
(ptr->*pmf)();
指向成員的指針實質是索引,而不是地址
在我看來不管是 virtual member functions 的指針還是 nonvirtual member functions 的指針
posted @
2011-06-01 13:45 unixfy 閱讀(190) |
評論 (0) |
編輯 收藏
第三章 Data 語意學
class object 的大小
·支持語言特性(virtual)自動添加的 data members
·alignment 的需要
empty virtual base class
Data Member 的綁定
·成員完全可見,可以在后面
·類型定義應該放在最前面
Data Member 的布局
static const 成員初始化
const 成員初始化
Data Member 的存取
static data members
static data member 編碼
name-mangling
nonstatic data members
origin._y = 0.0;
&origin + (&Point3d::_y - 1);
多態,指針或引用
但是如果是 (*p).foo() ?
繼承與 Data Member
多態
虛擬繼承
·virtual base class table
·virtual function table - offset
對象成員的效率
指向 Data Member 的指針
posted @
2011-05-28 13:22 unixfy 閱讀(87) |
評論 (0) |
編輯 收藏
怎樣把函數模板聲明為類模板的友元
給類模板聲明友元的函數模板有三種方式,分別為:
第一種方式,在模板類內部聲明友元的函數模板
第二種方式,在模板類內部聲明對應版本的友元函數模板實例化
需要前置聲明
這種方式是最為合理的方式
第三種方式,在模板類內部直接聲明友元函數,不涉及函數模板
這種情況只能在模板類內部一起把函數的定義寫出來,不能在外部實現,因為外部需要類型參數,而需要類型參數就是模板了
其實這種情況相當于一般的模板類的成員函數,也就是相當于一個函數模板
第二種方式也是一個函數模板,他們保持函數的參數類型和該模板類的實例一個類型
第一種方式更為靈活,他不會要求參數類型與模板類實例是一個類型,但是一般情況下我們也是按照一個類型使用的。
1 #include <iostream>
2 using namespace std;
3
4 //// 第一種方式,在模板類內部聲明友元的函數模板
5 //template <typename T>
6 //class C
7 //{
8 //private:
9 // T m[5];
10 //public:
11 // template <typename U>
12 // friend void foo(const C<U>& T);
13 //};
14 //
15 //template <typename T>
16 //void foo(const C<T>& t)
17 //{
18 // for (int i = 0; i < 5; ++i)
19 // {
20 // cout << t.m[i] << endl;
21 // }
22 //}
23
24 // 第二種方式,在模板類內部聲明對應版本的友元函數模板實例化
25 // 需要前置聲明
26 // 這種方式是最為合理的方式
27 template <typename T>
28 class C;
29
30 template <typename T>
31 void foo(const C<T>& t);
32
33 template <typename T>
34 class C
35 {
36 private:
37 T m[5];
38 public:
39 friend void foo<T>(const C<T>& t);
40 };
41
42 template <typename T>
43 void foo(const C<T>& t)
44 {
45 for (int i = 0; i < 5; ++i)
46 {
47 cout << t.m[i] << endl;
48 }
49 }
50
51 //// 第三種方式,在模板類內部直接聲明友元函數,不涉及函數模板
52 //// 這種情況只能在模板類內部一起把函數的定義寫出來,不能在外部實現,因為外部需要類型參數,而需要類型參數就是模板了
53 //// 其實這種情況相當于一般的模板類的成員函數,也就是相當于一個函數模板
54 //// 第二種方式也是一個函數模板,他們保持函數的參數類型和該模板類的實例一個類型
55 //// 第一種方式更為靈活,他不會要求參數類型與模板類實例是一個類型,但是一般情況下我們也是按照一個類型使用的。
56 //template <typename T>
57 //class C
58 //{
59 //private:
60 // T m[5];
61 //public:
62 // friend void foo(const C<T>& t)
63 // {
64 // for (int i = 0; i < 5; ++i)
65 // {
66 // cout << (t.m[i]) << endl;
67 // }
68 // }
69 //};
70
71 int main()
72 {
73 // C<int> c;
74 C<double> c;
75 foo(c);
76 return 0;
77 }
http://topic.csdn.net/u/20100619/21/c32066bb-dacd-4938-8f95-7345a522b0f6.html
http://topic.csdn.net/u/20100612/13/9365495d-b1d8-4e87-b704-23895acb1637.html
http://www.cnblogs.com/wswqwps/archive/2008/10/25/1319320.html
http://blog.csdn.net/dongzhongshu/archive/2011/02/22/6200466.aspx
posted @
2011-05-27 23:59 unixfy 閱讀(1883) |
評論 (0) |
編輯 收藏
swap 到底做了什么
swap 交換兩個內置數據類型的變量時,直接交換。
swap 交換自定義類型對象時,如果里面沒有成員指針,直接交換各個對應成員。
如果自定義類型中有指針成員,則是交換兩個指針的值,但是指針的指向的值得不到交換。
正是由于這個原因,可以用 swap 進行重載 operator = 時避免自賦值情況,而是生產一個臨時對象,然后與本對象 swap 即可。
關于重載 operator = 自賦值的情況,更詳細內容可以查看《Effective C++》
實驗程序:
1 #include <iostream>
2 using namespace std;
3
4 class Str
5 {
6 private:
7 char* s_;
8 public:
9 Str(const char* s = "")
10 {
11 s_ = new char[strlen(s) + 1];
12 if (s_ == 0)
13 {
14 cout << "test" << endl;
15 exit(1);
16 }
17 strcpy(s_, s);
18 }
19 // 定義拷貝構造函數,這里會被用于 operator =,swap
20 Str(const Str& rhs)
21 {
22 s_ = new char[strlen(rhs.s_) + 1];
23 if (s_ == 0)
24 {
25 cout << "test" << endl;
26 exit(1);
27 }
28 strcpy(s_, rhs.s_);
29 }
30 ~Str()
31 {
32 clear();
33 }
34 //// 常規的 operator = 重載實現方式,必須檢查自賦值
35 //// 因為如果不自賦值檢驗,對于自賦值現象如果不調用 clear,則 s_ 在 new 之后就改變,rhs 也改變,原來的丟失,后來的也不是合法內容
36 //// 如果調用 clear,不會內存泄露,但是 rhs 的內容被釋放掉,rhs 的內容也不是合法內容。
37 //// 如果檢驗自賦值,而沒有 clear,原來 *this 的那塊內存會被丟失,造成內存泄露。
38 //Str& operator = (const Str& rhs)
39 //{
40 // if (this != &rhs)
41 // {
42 // clear();
43 // s_ = new char[strlen(rhs.s_) + 1];
44 // if (s_ == 0)
45 // {
46 // exit(1);
47 // }
48 // strcpy(s_, rhs.s_);
49 // }
50 // return *this;
51 //}
52
53 // 改進的 operator,先用一個 temp 保持 rhs,然后 swap
54 // 這種方式不怕自賦值,因為如果是自賦值,也有一個備份 temp,操作值相同的兩個對象 *this 和 temp,直接交換不會影響結果
55 // 如果不是自賦值,不是交換 *this 和 rhs,而是交換 *this 和 rhs 的一個復制品 temp,最終 *this 得到的值就是 rhs 的一個副本,完成賦值
56 // 這種方式不用檢驗自賦值,所以可以省去每次調用時的自賦值檢驗,在基本上不會遇到自賦值檢驗的情況下,這種方法可以省去很多誤用的檢驗
57 // 但是它會每次生成一個副本,這樣做的效率與原來的非自賦值一樣,而且還需要一個 swap,但是這種方式是異常安全的,用對象來管理資源,資源分配即初始化
58 Str& operator = (const Str& rhs)
59 {
60 cout << "test" << endl;
61 Str temp(rhs);
62 // swap(*this, temp);
63 // 這里會引起遞歸調用,因為 operator = 調用 swap,swap 內部又調用 operator = ,一直遞歸下去,直到棧溢出
64 swap(s_, temp.s_);
65 // Effective C++ 中提到,可以定義一個成員函數 swap,用于交換兩個對象對應的數據成員。這樣可以防止無限遞歸。
66 // 另一種好的方式是除定義一個成員函數 swap 外,傳參類型為 值類型 T,這樣就可以直接交換返回。
67 // 這些方法的前提都是要有定義拷貝構造函數的。
68 return *this;
69 }
70
71 void clear()
72 {
73 delete [] s_;
74 }
75 void foo()
76 {
77 cout << s_ << endl;
78 }
79 };
80
81 int main()
82 {
83 int a = 3, b = 5;
84 swap(a, b);
85 cout << a << endl;
86 cout << b << endl;
87
88 Str s1("abc");
89 Str s2("xyz");
90 s1.foo();
91 s2.foo();
92
93 swap(s1, s2);
94 // 這里輸出兩個 test,我們得知,有兩個賦值操作
95 // 可以推測 swap 的內部實現是 T t(s2), s2 = s1, s1 = t;
96 s1.foo();
97 s2.foo();
98
99 s2 = s1;
100 s1.foo();
101 s2.foo();
102
103 return 0;
104 }
posted @
2011-05-27 22:14 unixfy 閱讀(892) |
評論 (0) |
編輯 收藏
棧和堆是內存中的部分。安裝地址的變化規則,棧是向下生長的,堆是向上增長的。
這里對棧和堆的地址生長情況做了一個實現。
更好的內容有 Computer System:A Programmer's Perspective 《深入理解計算機系統》
1 #include <iostream>
2 using namespace std;
3
4 int main()
5 {
6 int i = 1;
7 int j = 2;
8 int k = 3;
9 cout << &i << endl;
10 cout << &j << endl;
11 cout << &k << endl;
12 // 棧是向下生長的,所以地址遞減
13
14 int a[3];
15 cout << &a[0] << endl;
16 cout << &a[1] << endl;
17 cout << &a[2] << endl;
18 // 棧還是向下生長的,但是對于一個數組來說從第一個元素到后面的元素
19 // 其每個元素的地址是遞增的。所以最后一個元素是在最上面的,也就是
20 // 與前面在棧上定義的元素挨著,第一個元素在最下面
21
22
23 cout << a[3] << endl;
24 cout << a[5] << endl;
25 // 這里 a[5] 輸出 3,a + 5 將達到變量 k 的地址 &k,所以 *(a + 5) = k
26
27
28 int* b = new int[3];
29 cout << &b[0] << endl;
30 cout << &b[1] << endl;
31 cout << &b[2] << endl;
32 // 堆是向上生長的,第一個元素在最下面
33
34 // 不管是在堆還是在棧上的數組,數組中的元素的地址都是隨著元素的位
35 // 置遞增而遞增的。
36 // 只不過在棧上的元素順序與棧的增長方向相反,在堆上數組的元素的順
37 // 序與堆的增長方向相同。
38
39 return 0;
40 }
posted @
2011-05-27 01:00 unixfy 閱讀(402) |
評論 (0) |
編輯 收藏
關于訪問權限和繼承方式
訪問權限有三種:public、protected、private
繼承也有三種:public、protected、private,這里不考慮 virtual 繼承。
繼承時的權限,不是針對本類內的訪問權限,而是針對該派生類的客戶端代碼(包括其派生類)的訪問權限。
即是,對于基類中的 public、protected 成員,如果一個派生類 private 繼承自該基類,則這些成員還是可以在派生類中訪問的,只是不能在該派生類的客戶代碼中被直接訪問,或者在該派生類的派生類中直接訪問。
也就是說,繼承的方式是針對派生類的客戶端代碼來講的,對派生類內部不起作用,不管是 public、protected、private 繼承,派生類中總是可以訪問基類中的 public、protected 成員,基類中的 private 成員永遠不能在派生類中直接訪問,不論通過哪種方式。
歸納一下:
成員訪問權限 繼承方式 派生類中能否訪問 派生類的派生類中 派生類的客戶端代碼
public public 能 能 能
public protected 能 能 不能
public private 能 不能 不能
protected public 能 能 不能
protected protected 能 能 不能
protected private 能 不能 不能
private public 不能 不能 不能
private protected 不能 不能 不能
private private 不能 不能 不能
從這個表中,我們更能清除地看到成員訪問權限和繼承方式之間的組合,對派生類中的訪問、派生類的派生類中的訪問、派生類的客戶端代碼的訪問控制情況。
繼承的方式是在原有基類訪問權限的基礎上,給在派生類的訪問權限又加了一個效應。取兩個中最嚴格的那個權限,這個取得的權限是派生類成員的訪問權限,而這種訪問權限對派生類的客戶端代碼和派生類的派生類代碼其訪問控制作用。
posted @
2011-05-27 00:20 unixfy 閱讀(456) |
評論 (0) |
編輯 收藏
隊列的兩個主要操作:入隊列、出隊列
棧的兩個主要操作:入棧、出棧
入隊列對應入棧
出隊列是出最早的,出棧是出最晚的
使用 360 瀏覽器,有個不錯的功能是可以恢復標簽,你關閉一個標簽,這個標簽就會進入待恢復表,如果待恢復表慢了,新加標簽,最早的標簽會消失,這是 FIFO 隊列。
但是如果點擊恢復標簽隊列,會恢復最近關閉的標簽,也就是最晚進入待恢復表中的標簽,所以這又是一種 LIFO 棧。
待恢復表既具有添加標簽的 FIFO 隊列性質,又具有恢復標簽并移除標簽的 LIFO 棧性質。
實現一個數據結構,使其既具有 FIFO 隊列的性質,又具有 LIFO 棧的性質。
由于標簽有很多,這里使用循環表來實現這個數據結構,早期的標簽會隨著新加入的標簽被覆蓋。
注意連續關閉兩個相同的標簽,第二次關閉時,不會將這個標簽存入待恢復表中。
這個表主要有三個操作
·入隊列
·出隊列
·出棧
沒有入棧,其實入棧也就是入隊列。
實現:
1 #include <iostream>
2 using namespace std;
3
4 class Table360
5 {
6 private:
7 int capacity_;
8 int* data_;
9 int size_;
10 int head_;
11 int tail_;
12 public:
13 Table360(int c = 10) : capacity_(c)
14 {
15 data_ = new int[capacity_];
16 if (data_ == 0)
17 {
18 exit(1);
19 }
20 memset(data_, 0, sizeof (int) * capacity_);
21 size_ = 0;
22 head_ = 0;
23 tail_ = -1;
24 }
25 Table360(const Table360& t) : capacity_(t.capacity_)
26 {
27 data_ = new int[capacity_];
28 if (data_ == 0)
29 {
30 exit(1);
31 }
32 memset(data_, 0, sizeof (int) * capacity_);
33 size_ = t.size_;
34 head_ = t.head_;
35 tail_ = t.tail_;
36 for (int i = 0; i < size_; ++i)
37 {
38 data_[(head_+i) % capacity_] = t.data_[(t.head_ + i) % t.capacity_];
39 }
40 }
41 void swap_(Table360& t)
42 {
43 swap(capacity_, t.capacity_);
44 swap(data_, t.data_);
45 swap(size_, t.size_);
46 swap(head_, t.head_);
47 swap(tail_, t.tail_);
48 }
49 Table360& operator = (const Table360& t)
50 {
51 Table360 temp(t);
52 swap_(temp);
53 return *this;
54 }
55 ~Table360()
56 {
57 delete [] data_;
58 capacity_ = 0;
59 size_ = 0;
60 head_ = 0;
61 tail_ = 0;
62 }
63 int size()
64 {
65 return size_;
66 }
67 bool empty()
68 {
69 return size_ == 0;
70 }
71 int top()
72 {
73 return data_[head_];
74 }
75 void enQueue(int item)
76 {
77 if (size_ >= capacity_)
78 {
79 deQueue();
80 }
81 tail_ = (tail_ + 1) % capacity_;
82 data_[tail_] = item;
83 ++size_;
84 //if (size_ >= capacity_)
85 //{
86 // head_ = (head_ + 1) % capacity_;
87 // --size_;
88 // tail_ = (tail_ + 1) % capacity_;
89 // data_[tail_] = item;
90 // ++size_;
91 //}
92 //else
93 //{
94 // tail_ = (tail_ + 1) % capacity_;
95 // data_[tail_] = item;
96 // ++size_;
97 //}
98 }
99 void deQueue()
100 {
101 head_ = ++head_ % capacity_;
102 --size_;
103 }
104 // 其實沒有入棧操作,入棧即是入隊列
105 void push(int item)
106 {
107 enQueue(item);
108 }
109 int pop()
110 {
111 int tmp = tail_;
112 tail_ = (tail_ + capacity_ - 1) % capacity_;
113 --size_;
114 return data_[tmp];
115 }
116 int stacktop()
117 {
118 return data_[tail_];
119 }
120 };
121
122 int main()
123 {
124 Table360 t(20);
125 cout << t.size() << endl;
126 for (int i = 0; i < 100; ++i)
127 {
128 t.enQueue(i);
129 }
130 cout << t.size() << endl;
131 // cout << t.top() << endl;
132 while (!t.empty())
133 {
134 // cout << t.pop() << ' ';
135 cout << t.stacktop() << ' ';
136 t.pop();
137 }
138 cout << endl;
139 return 0;
140 }
其他鏈接:
http://zh.wikipedia.org/wiki/%E9%98%9F%E5%88%97
http://zh.wikipedia.org/wiki/%E5%A0%86%E6%A0%88
http://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84
http://student.zjzk.cn/course_ware/data_structure/web/zhanhuoduilie/zhanhuoduilie3.2.1.htm
http://student.zjzk.cn/course_ware/data_structure/web/zhanhuoduilie/zhanhuoduilie3.1.1.htm
http://student.zjzk.cn/course_ware/data_structure/web/main.htm
posted @
2011-05-26 00:48 unixfy 閱讀(139) |
評論 (0) |
編輯 收藏
《深度探索 C++ 對象模型》讀書筆記——第一章 關于對象
C++ 對象模型
·語言中直接支持面向對象程序設計的部分
·對于各種支持的底層實現機制
virtual table
理解底層實現模型的好處有
·寫出效率較高的代碼
·有更好的自信心
關于對象
布局、存取時間來自于
·virtual: virtual function, virtual base class
·derived class 與 base class 的轉換
class data members: static, nonstatic
class member functions: static, nonstatic, virtual
1.簡單對象模型 Simple Object Model
slots
指向成員的指針
2.表格驅動對象模型
data member table
member function table: slots
Member Table 對象模型
支持 virtual functions
3.C++ 對象模型
virtual table (vtbl)
vptr: constructor, destructor, copy assignment
type_info object for RTTI(運行時類型識別)
優點:空間和存取時間的效率
缺點:會導致重新編譯
bptr
(*px->vtbl[2])(px);
(*px->vtbl[1])(px);
_delete(px);
vptr
virtual table
-----
address -> type_info for X
address -> X::~X()
address -> X::foo()
-----
pt->vtbl[0]
pt->vtbl[1]
pt->vtbl[2]
關鍵字所帶來的差異
組合而非繼承是把 C 和 C++ 結合在一起的唯一可行方法
conversion 運算符
operator C_point()
{
return _c_point;
}
對象的差異
C++ 程序設計模型直接支持三種程序設計典范 programming paradigms
·程序模型 procedural model
·抽象數據類型模型 abstract data type model
·面向對象模型 object-oriented model
C++ 支持多態的方法
·隱含轉化 Shape* ps = new circle();
·virtual function ps->rotate();
·dynamic_cast, typeid
if (Circle* pc = dynamic_cast<Circle*>(ps))
{
...
}
class object 內存
·nonstatic data members
·alignment
·virutal(virtual functions, virtual base class)
dynamic_cast<Base*>
OB: object-based
OO: object-oriented
posted @
2011-05-25 18:48 unixfy 閱讀(144) |
評論 (0) |
編輯 收藏