原创 从一个例子中去体会纯虚函数的用法

2010-4-26 12:21 1734 4 4 分类: MCU/ 嵌入式

 


作者:王姗姗,华清远见嵌入式学院讲师。


首先先请大家来看下面的一段代码:
        #include <iostream>
        using namespace std;
        class Shape
        {
        public:
                virtual float area() =0;
                virtual float volume() =0;
                virtual void shapeName() =0;
        };


class Point:public Shape
        {
        public:
                Point(float=0,float=0);
                void setPoint(float,float);
                float getX( ) const {return x;}
                float getY( ) const {return y;}
                virtual void shapeName() const {cout<<"Point:";}
                friend ostream & operator<<(ostream &,const Point &);
        protected:
                float x,y;
        };


Point::Point(float a,float b)
        {
                x=a;
                y=b;
        }


void Point::setPoint(float a,float b)
        {
                x=a;
                y=b;
        }


ostream & operator<<(ostream &output,const Point &p)
        {
                output<<"["<<p.x<<","<<p.y<<"]";
                return output;
        }


int main( )
        {
                Point point(3.2,4.5);
                point.shapeName();
                cout<<point<<endl;


        Shape *pt;
                pt=&point;
                pt->shapeName( );
                cout<<"x="<<point.getX( )<<",y="<<point.getY( )<<"\narea="<<pt->area( )<<"\nvolume="<<pt->volume()<<"\n\n";


        return 0;
        }


本来我的初衷是想定义一个抽象基类shape,由它派生出5个派生类:circle,square,rectangle,trapezoid,triangle.这只是其中的一部分,用来说明纯虚函数怎样来使用。但是编译的时候出现了:


点击看大图


试了很多办法,解决这段程序的几个解决途径:


第一种途径:


class Shape
        {
        public:
                virtual float area() const =0;
                virtual float volume()const=0;
                virtual void shapeName()const =0;
        };


并在后面Ponit类中添加:


virtual float area() const {}
        virtual float volume()const{}


原因:


1)因为以后声明的area() 、volume()、shapeName()都是常成员函数,在C++中,const关键字是可以被用于参与对重载函数的区分。也就是说:


void shapeName()const;
        void shapeName();


这两个函数是不一样的。常对象只能调用常方法,而普通对象在声明同名普通函数的情况下调用普通函数,如果没有声明同名的普通函数,就会调用常方法。


2)纯虚函数没有函数体。对于由shape派生而来的point类来说,因为没有显式的去声明area() 、volume()这两个没有用到的函数,导致这两个函数仍然是纯虚函数。而包含纯虚函数的类称为抽象类,抽象类只能作为基类来使用,不能声明抽象类的对象。那么这样就出现了上面报的那个错误。


故:所以要让程序能够编译通过,我们要选择用纯虚函数解决问题,就必须在继承类中对纯虚函数进行显式的声明和实现。这样才可以用由抽象类派生而来的派生类来定义对象。


第二种途径:
        class Shape
        {
        public:
                virtual float area() const {};
                virtual float volume()const{};
                virtual void shapeName()const {};
        };


原因:


我们用虚函数去替代了纯虚函数。添加const是为了和Point类的const方法同步,都是常成员函数。在本题中,用虚函数去替代了纯虚函数,好处就是在后面的Point类中不用显式的再将这几个没有给功能的函数再声明和实现。


虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数。


在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。


故:要让程序能够编译通过,我们要选择用虚函数,就把这留在后面再重新定义功能的三个函数写成虚函数的形式。这样就可以用指向基类指针或引用根据指针指向的对象的类去调用指向对象的方法了。

文章评论0条评论)

登录后参与讨论
我要评论
0
4
关闭 站长推荐上一条 /2 下一条