多态对象列表
2009-07-05 17:02
本文共约 1031 字
预计阅读时间约 3 分钟
之所以C++有时不被当作高级语言,那是因为它是一门对变量内存布局很讲究的语言,每个变量所占用的空间大小如果发生变化,有时候是会影响程序的结果的。例如在同时使用多态对象和数组技术时,就容易出现这样的问题。
我们首先来看看高级语言C#写的一段小程序:
1using System;
2using System.Collections.Generic;
3
4namespace Test
5{
6 class Base
7 {
8 public virtual void Foo() { Console.WriteLine("From Base"); }
9 }
10
11 class Derived : Base
12 {
13 public override void Foo() { Console.WriteLine("From Derived"); }
14 }
15
16 class Program
17 {
18 static void Main(string[] args)
19 {
20 List<Base> a = new List<Base>();
21 a.Add(new Base());
22 a.Add(new Derived());
23
24 foreach (Base b in a)
25 {
26 b.Foo();
27 }
28 }
29 }
30}程序的执行结果是:
1From Base
2From Derived很简单的程序,把基类和派生类分别实例化出来的对象放入列表中,然后逐个取出来。结果也如同我们所预料的那样,分别执行了基类和派生类的成员函数(方法)。然而到了C++中,却没有那么理想了:
1#include <iostream>
2#include <vector>
3
4class Base
5{
6 public:
7 virtual void Foo() { std::cout << "From Base" << std::endl; }
8};
9
10class Derived : public Base
11{
12 public:
13 virtual void Foo() { std::cout << "From Derived" << std::endl; }
14};
15
16int main()
17{
18 std::vector<Base> a;
19 a.push_back(Base());
20 a.push_back(Derived());
21
22 for (size_t i = 0; i < a.size(); i++)
23 {
24 a[i].Foo();
25 }
26 return 0;
27}程序的执行结果是:
1From Base
2From Base原来,被放入列表后,派生类对象也被“截断”成为基类对象,因而只能调用到基类的成员函数了。这就是C++中一个很重要的原则:**想要实现多态,必须使用指针或引用!**这在《More Effective C++》中也有详细地阐述(“条款3:不要使用多态性数组”)。然而,引用是无法放入列表容器中的,因此只能使用对象指针的数组:
1// ...
2// Base 和 Derived 类定义同前
3// ...
4int main()
5{
6 std::vector<Base*> a;
7 a.push_back(new Base());
8 a.push_back(new Derived());
9
10 for (size_t i = 0; i < a.size(); i++)
11 {
12 a[i]->Foo();
13 }
14
15 for (size_t i = 0; i < a.size(); i++)
16 {
17 delete a[i];
18 }
19 return 0;
20}这时结果就符合我们的预期了:
1From Base
2From Derived但比较麻烦的是,我们必须在结束使用这些 new 出来的对象时,用 delete 逐个销毁它们。所幸,boost 中有一利器:boost::shared_ptr,能帮我们分担点这方面的焦虑:
1// ...
2#include <boost/shared_ptr.hpp>
3// ...
4// Base 和 Derived 类定义同前
5// ...
6int main()
7{
8 std::vector<boost::shared_ptr<Base>> a;
9 a.push_back(boost::shared_ptr<Base>(new Base()));
10 a.push_back(boost::shared_ptr<Base>(new Derived()));
11
12 for (size_t i = 0; i < a.size(); i++)
13 {
14 a[i]->Foo();
15 }
16 return 0;
17}所以,强烈期盼 boost 早日成为众多 C++ 编译器的标准支持!