关于虚函数、纯虚函数、抽象类的疑惑小记

    在进行MFC编程的过程中,在需要继承一个MFC类时想到其有许多虚函数,这些函数并没有一一去继承啊,印象中虚函数相当于Java的抽象类(实则不然),而继承抽象类的非抽象类时必须去实现所有的抽象函数。那么在C++中,虚函数应该是怎样的呢。伴随着这个疑惑,进行简单的编程验证。

疑惑起因:子类是否必须要去继承父类的虚函数?

代码:

class Father
{
public:
virtual void fun1(){cout <<"father"<<"\n";};
};
class Son : public Father
{

};
void main()
{
Son *son=new Son();
son->fun1();
return;
}

编译及执行没有错误,输出:father。因此,虚函数是可以不去实现的。

注:Java中abstract类的特性——

1)abstract类中可以有abstract方法,也可以有其他非abstract方法,甚至可以没有abstract方法,而非abstract类中不能有abstract方法;

2)abstract类不能用new创建该类的对象,其非abstract类的子类必须重写父类的abstract方法,其abstract类的子类则可以重写也可以继承父类的abstract方法;

3)abstract类虽不能使用new创建该类的对象,但是其可以成为其子类对象的向上转型对象,该对象可以调用子类重写的方法。


下面就C++的虚函数、纯虚函数、抽象类进行一个较为系统的总结:


1、虚函数

1)为何要有虚函数?如果不使用虚函数会发生什么?

class Father                   //基类
{
public:
void fun1(){cout <<"father"<<"\n";}//非虚函数
};

class Son : public Father   //派生类
{
public:
void fun1(){cout <<"son"<<"\n";}//重写fun1
};

void main()
{
Father father;             //Father对象
Father *pFather = &father;     //Father对象的指针
Son son;                     //Son
Son *pSon = &son;        //Son对象的指针


pFather->fun1();           //输出“father”
pSon->fun1();               //输出“son”

pFather = pSon;            //基类指针指向派生类对象
pFather->fun1();           //输出“father”

return;
}

上述代码的输出已经在注释中说明,可见通过指针调用的成员函数只与指针类型有关,而与此刻指向的对象无关。下面将基类的fun1函数改为虚函数,如下:

class Father                   //基类
{
public:
virtual void fun1(){cout <<"father"<<"\n";}//虚函数
};

class Son : public Father   //派生类
{
public:
void fun1(){cout <<"son"<<"\n";}//重写fun1
};

void main()
{
Father father;             //Father对象
Father *pFather = &father;     //Father对象的指针
Son son;                     //Son
Son *pSon = &son;        //Son对象的指针


pFather->fun1();           //输出“father”
pSon->fun1();               //输出“son”

pFather = pSon;            //基类指针指向派生类对象
pFather->fun1();           //输出“son”

return;
}

    结果是,当基类指针指向派生类对象时,向指针所指的对象发消息,则执行的是派生类对象对应的函数代码。可以想象,若使用基类指针指向不同的派生类对象,向指针所指向的对象发消息,则所执行的函数代码由各个派生类对象决定,这是C++多态的意义之一。值得一提的是,若将上述代码中“pFather->pSon;pFather->fun1();”改成“father=son;father.fun1()”则输出为“father”,改为“Father & fa=son;fa.fun1()”则输出为“son”。由此可见,C++一般通过指针或引用来实现这种“动态联编”。

注:虚函数的特性——

1)虚函数无论被继承多少次,仍是虚函数,派生类对基类的虚函数进行重新定义时,virtual可写可不写(仍是虚函数),特别地如果派生类中定义的函数只是函数名和基类的虚函数名相同,而函数原型不同(参数个数及类型不同),则C++降之视为函数的重载(不默认是虚函数);

2)静态成员函数、构造函数、友元函数都不能声明为虚函数,因为它们依赖于对象。此外,全局函数、内联函数也不能声明为虚函数;

3)一般只将protected或public部分的成员函数声明为虚函数;

4)析构函数可以是虚函数;

5)只有通过基类指针或引用访问基类的虚函数时,才能获得运行时的多态性;

6)虚函数可以是另一个类中的友元函数。(此句未懂!)

7)派生类中可以将基类中的非虚函数重新定义为虚函数,可以通过该派生类指针或引用访问该派生类的这个虚函数,以获得运行时的多态性。(自己总结得)


2、纯虚函数

    纯虚函数的形式:virtual 返回值类型 函数名(参数表)=0;也可以带函数体,即virtual 返回值类型 函数名(参数表)=0{函数体}

    声明了虚函数的基类,只有通过基类指针或引用访问基类的虚函数时,才能获得运行时的多态性,同时该类仍然可以实例化。与之不同的是,

1)声明了纯虚函数的类则不能建立对象,只能声明指向该类的指针变量和引用变量(声明了纯虚函数的类称为抽象类,类中可以有其他非纯虚函数);

另外值得注意的是,

2)抽象类的派生类中若对“纯虚函数”没有重新定义,则这个派生类还是一个抽象类;

3)其非抽象类的派生类中,必须实现基类的所有纯虚函数。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值