C++ 面向对象编程(1)

在<<c++ primer>>第四版的第15章中详细讲解了类的定义,继承关系,多态。这里主要实现这一章中的例子。

首先看定义Item_base对象,文件为Item_Base.h。

 1 #pragma once
 2 #ifndef __ITEMBASE__
 3 #define __ITEMBASE__
 4 
 5 #include <string>
 6 #include <iostream>
 7 
 8 class Item_base
 9 {
10 public:
11     Item_base(const std::string &book="",double sales_price=0.0):isbn(book),price(sales_price){}
12     std::string book() const
13     {
14         return isbn;
15     }
16     virtual double net_price(std::size_t n) const
17     {
18         std::cout << "base.net_price " << std::endl;
19         return n*price;
20     }
21     virtual void print() const
22     {
23         std::cout << "base class called..." << std::endl;
24     }
25     virtual ~Item_base() {}
26 
27 private:
28     std::string isbn;
29 protected:
30     double price;
31 };
32 
33 
34 #endif // !__ITEMBASE__
View Code

再看继承类Bulk_item,这里使用了最常见的public继承。文件为Bulk_Item.h。

 1 #pragma once
 2 #ifndef __BULKITEM__
 3 #define __BULKITEM__
 4 #include "Item_Base.h"
 5 #include <iostream>
 6 
 7 
 8 class Bulk_item:public Item_base
 9 {
10 public:
11     Bulk_item(const std::string &book, double sales_price, std::size_t qty = 0, double disc_rate = 0.0)
12         :Item_base(book, sales_price), min_qty(qty), discount(disc_rate) {}
13 
14     double net_price(std::size_t n) const
15     {
16         std::cout << "derived.net_price " << std::endl;
17         if (n >= min_qty)
18         {
19             return n*(1 - discount)*price;
20         }
21         else
22         {
23             return n*price;
24         }
25     }
26 
27     virtual void print() const
28     {
29         std::cout << "derived class called..." << std::endl;
30     }
31 
32 private:
33     std::size_t min_qty;
34     double discount;
35 };
36 
37 
38 #endif // !__BULKITEM__
View Code

调用main方法的cpp文件为:ClassSample.cpp。

 1 // ClassSample.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include "Item_Base.h"
 6 #include <iostream>
 7 #include "Bulk_Item.h"
 8 #include <vector>
 9 
10 
11 using namespace std;
12 
13 int main()
14 {
15     Item_base base("1",1);
16     Bulk_item derived("2",2,1,0.5);
17     Item_base &obj1 = derived;
18     Item_base *obj2 = &derived;
19     cout << "begin to test dynamic call.." << endl;
20     obj1.print();
21     obj2->print();
22     vector<Item_base> vect;
23     vect.push_back(base);
24     vect.push_back(derived);
25     cout << "begin to loop for object.." << endl;
26     vector<Item_base>::iterator begin = vect.begin();
27     while (begin != vect.end())
28     {
29         begin->print();
30         ++begin;
31     }
32     cout << "begin to loop for pointer.." << endl;
33     
34     Item_base *base1 = new Item_base("base",1);
35     Item_base *derived1 = new Bulk_item("derived",2);
36     vector<Item_base* > vect2;
37     vect2.push_back(base1);
38     vect2.push_back(derived1);
39     vector<Item_base* >::iterator begin_pointer = vect2.begin();
40     while (begin_pointer != vect2.end())
41     {
42         (*begin_pointer)->print();
43         ++begin_pointer;
44     }
45     delete base1;
46     delete derived1;
47     system("pause");
48     return 0;
49 }
View Code

在Item_base对象中,有一个print虚函数,这个虚函数在Bulk_item中也有被实现。根据多态的定义,我们使用指针和引用分别调用该虚函数。最终得到的结果是,Bulk_item对象中的print方法被执行。

其次看一下,关于容器和对象。这里使用了vector容器。该容器包含的对象类型是Item_base对象,如果在该容器中存放了Item_base的子类,那么子类会被截断(c++ primer 15.7)。

参考代码begin to loop for object下面的执行结果。

所以我们可以将容器定义为指向Item_base对象的指针,这样就可以存放子类对象。但是,既然是指针,那么需要我们手工来管理这些指针。因为我们要确保,vector对象存在的时候,这些指针所指向的对象也是必须存在的。

参考代码begin to loop for pointer.. 下面的执行结果。

放一张cpp 文件的执行结果:

为了避免我们手工管理这些指针,c++ primer 的15.8 节讲解了句柄对象。下面来看看。

句柄,就是基类指针的包装类,这个包装类自己管理指针。根据个人的学习,我总结了句柄实现的两个功能:

  1. 句柄必须管理的是指针。
  2. 句柄必须管理指针的删除。

因为需要通过句柄来实现多态,所以管理的对象必须是指针。所以也必须管理指针的删除。说到底,就是指针的管理。

来看这个句柄的实现:

 1 #pragma once
 2 #ifndef __SALEITEM__
 3 #define __SALEITEM__
 4 
 5 #include "Item_Base.h"
 6 #include "Bulk_Item.h"
 7 
 8 using namespace std;
 9 
10 class Sale_item
11 {
12 
13 public:
14     Sale_item() :p(0), use(new size_t(1)){}
15     Sale_item(const Item_base &item):p(item.clone()),use(new size_t(1)){}
16     Sale_item(const Sale_item &i) :p(i.p), use(i.use) { ++*use; }
17     ~Sale_item() { decr_use(); }
18     Sale_item& operator=(const Sale_item &rhs)
19     {
20         if (p != rhs.p)
21         {
22             ++*rhs.use;
23             decr_use();
24             p = rhs.p;
25             use = rhs.use;
26             return *this;
27         }
28         return *this;
29     }
30     Item_base *operator->() 
31     {
32         if (p)return p;
33         throw logic_error("unbound Sale_item");
34     }
35     Item_base &operator*()
36     {
37         if (p)return *p;
38         throw logic_error("unbound Sale_item");
39     }
40 
41 private:
42     Item_base *p;
43     size_t *use;
44     void decr_use()
45     {
46         if (--*use == 0)
47         {
48             delete p;
49             delete use;
50         }
51     }
52 
53 };
54 
55 #endif // !__SALEITEM__
View Code

句柄既然是包装类,因此我们需要创建一个类,其中有两个成员,一个是父类指针,另外一个是引用计数。因为成员是指针,所以我们需要实现析构函数,根据三法则,我们同时需要自己实现复制控制。

另外,因为句柄必须管理的是指针,因此我们需要其管理的对象必须能够自己返回一个指针,所以在Item_base和Bulk_item对象中都有一个clone函数用来返回该对象的指针。看这两个对象的对应实现,在之前的基础上实现了clone函数。完整代码如下:

Item_base实现如下:

 1 #pragma once
 2 #ifndef __ITEMBASE__
 3 #define __ITEMBASE__
 4 
 5 #include <string>
 6 #include <iostream>
 7 
 8 class Item_base
 9 {
10 public:
11     Item_base(const std::string &book="",double sales_price=0.0):isbn(book),price(sales_price){}
12     std::string book() const
13     {
14         return isbn;
15     }
16     virtual double net_price(std::size_t n) const
17     {
18         std::cout << "base.net_price " << std::endl;
19         return n*price;
20     }
21     virtual void print() const
22     {
23         std::cout << "base class called..." << std::endl;
24     }
25     virtual ~Item_base() {}
26 
27     virtual Item_base* clone() const
28     {
29         return new Item_base(*this);
30     }
31 
32 private:
33     std::string isbn;
34 protected:
35     double price;
36 };
37 
38 
39 #endif // !__ITEMBASE__
View Code

Bulk_item实现如下:

 1 #pragma once
 2 #ifndef __BULKITEM__
 3 #define __BULKITEM__
 4 #include "Item_Base.h"
 5 #include <iostream>
 6 
 7 
 8 class Bulk_item:public Item_base
 9 {
10 public:
11     Bulk_item(const std::string &book, double sales_price, std::size_t qty = 0, double disc_rate = 0.0)
12         :Item_base(book, sales_price), min_qty(qty), discount(disc_rate) {}
13 
14     double net_price(std::size_t n) const
15     {
16         std::cout << "derived.net_price " << std::endl;
17         if (n >= min_qty)
18         {
19             return n*(1 - discount)*price;
20         }
21         else
22         {
23             return n*price;
24         }
25     }
26 
27     virtual void print() const
28     {
29         std::cout << "derived class called..." << std::endl;
30     }
31 
32     virtual Bulk_item* clone() const
33     {
34         return new Bulk_item(*this);
35     }
36 
37 
38 private:
39     std::size_t min_qty;
40     double discount;
41 };
42 
43 
44 #endif // !__BULKITEM__
View Code

看看cpp测试代码,主要看begin to loop for handler 以下部分:

 1 // ClassSample.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include "Item_Base.h"
 6 #include <iostream>
 7 #include "Bulk_Item.h"
 8 #include <vector>
 9 #include "Sale_Item.h"
10 
11 using namespace std;
12 
13 int main()
14 {
15     Item_base base("1",1);
16     Bulk_item derived("2",2,1,0.5);
17     Item_base &obj1 = derived;
18     Item_base *obj2 = &derived;
19     cout << "begin to test dynamic call.." << endl;
20     obj1.print();
21     obj2->print();
22     vector<Item_base> vect;
23     vect.push_back(base);
24     vect.push_back(derived);
25     cout << "begin to loop for object.." << endl;
26     vector<Item_base>::iterator begin = vect.begin();
27     while (begin != vect.end())
28     {
29         begin->print();
30         ++begin;
31     }
32     cout << "begin to loop for pointer.." << endl;
33     
34     Item_base *base1 = new Item_base("base",1);
35     Item_base *derived1 = new Bulk_item("derived",2);
36     vector<Item_base* > vect2;
37     vect2.push_back(base1);
38     vect2.push_back(derived1);
39     vector<Item_base* >::iterator begin_pointer = vect2.begin();
40     while (begin_pointer != vect2.end())
41     {
42         (*begin_pointer)->print();
43         ++begin_pointer;
44     }
45     delete base1;
46     delete derived1;
47 
48     cout << "begin to loop for handler.." << endl;
49     vector<Sale_item> vect3;
50     Item_base base2("base2", 1);
51     Bulk_item derived2("derived2", 2);
52     vect3.push_back(Sale_item(base2));
53     vect3.push_back(Sale_item(derived2));
54 
55     vector<Sale_item>::iterator begin1 = vect3.begin();
56     while (begin1 != vect3.end())
57     {
58         (*begin1)->print();
59         ++begin1;
60     }
61     
62     system("pause");
63     return 0;
64 }
View Code

执行结果如下,vector容器是基于句柄来进行操作的。

posted on 2017-05-15 14:57  ^~~^  阅读(235)  评论(0编辑  收藏  举报

导航