明明白白c++ 继承 接口继承和实现继承

前言

继承,为什么要设计继承呢?这个是面向对象的一个重要概念,减少设计的复杂度。通过继承可以减少代码量。

c++中的继承形式比较多,公有继承,保护继承,和私有继承。如果是为了对付考试,那么你还是需要弄清楚这些概念。但是实际上公有继承比较有用,其他的可以忽略掉,大多数情况下他们很不实用,而且还用弄错。所以google推荐使用组合的方式来代替那些私有和保护继承。

组合和继承,has和is的关系。这里就不讨论了。


就继承的目的来看,包括接口继承和实现继承两种。

根据前面讲过的虚函数的概念,这这里又要用到。

本文参考

http://dev.yesky.com/218/2145218_2.shtml

一  纯虚函数。-----------接口继承

纯虚函数的作用是为了实现接口。

这里拿移动为例子吧,因为很多讲这里的时候都是拿形状为例子的。用自己的例子将一东西,才能让自己学习明白。

比如我做游戏设计的,人型和飞鸟两种角色。他们的移动肯定是不同的,会播放不用的动画效果。(例如dota里面的普通英雄和蝙蝠火焰状态)

#include <iostream>
using namespace std;
class character
{
public:
   virtual void  move()=0;
   void id();
};
class people:public character
{
public:
	virtual void  move();
};
class bird:public character
{
public:
	virtual void  move();
};
void people::move()
{
   cout<<"people move"<<endl;
}
void bird ::move()
{
  cout<<"bird move"<<endl;
}

int main()
{
 character c;//报错
 people p;
 bird b; 
 p.move(); 
 b.move();
 c.move();//报错
}

注释掉报错那句话上面的程序的输出结果是

people move

bird move

有几个细节需要注意:

1 如果你用class 定义类,那么类里面默认声明是private,类之间的继承关系是private,所以一定养成好的习惯明确用public,private,protected来表示,因为你很可能记混淆struct 和class的默认关键字。

2 如果是接口继承一定要定义成纯虚函数。可以认为只是个接口,随着子类不同,属性不用。父类没有明确的定义,是抽象的概念。

3 含义纯虚函数的类叫做抽象类,它不能声明对象,因为它是抽象的,它没有具体形态,所以也就不存在。


二 虚函数--------------接口继承+ 缺省实现

这里我们拿两个英雄来说,lina 和 jugg 火女和剑圣,大家都知道剑圣有跳劈,攻击时候会是攻击力的倍数值,但是普通英雄并没有。

#include <iostream>
using namespace std;
class character
{
public:
   virtual void attact(character &c);
   int getLife(); 
   void setLife(int value);  
   void setAccactValue(int value);  
   int getAccactValue();   
private:
   int life;   
   int accactValue;
};
int character::getAccactValue()
{
   return accactValue;
}
void character::setAccactValue(int value)
{
      accactValue = value;
}
int character::getLife()
{
	return life;
}
void character::attact(character &c)
{
    int life = c.getLife();
   c.setLife(life - getAccactValue());
   cout<<"common acctact"<<endl;
}

void character::setLife(int value)
{
   if (value > 0)
      life = value;
   else
      life = 0;

}
class lina:public character
{
};
class jugg:public character
{
public:
    virtual void attact(character &c);
	float randomRate();

};
float jugg::randomRate()
{
   //这里为了简化写成1.5,实际是个区间的随机数
   return 1.5;
}
void jugg::attact(character &c)
{

int life = c.getLife();
c.setLife(life - getAccactValue() * randomRate());
cout<<"jugg acctact"<<endl;
}

int main()
{
 lina l;
 jugg   j;
 l.setLife(100);
 l.setAccactValue(10);
 j.setLife(100);
 j.setAccactValue(10);
 l.attact(j);
 j.attact(l);
 cout<<"lina's life"<<l.getLife()<<endl;
 cout<<"jugg's life"<<j.getLife()<<endl;
}

上面一段代码描述了jugg和lina相互攻击的过程。

其中有一个地方需要注意攻击函数传递的对象要加&,这样才能改变传入的对象,不然就是值传递。你会发现最后两个英雄打来打去,生命都不会减少。

http://blog.csdn.net/mlkiller/article/details/8754330如果不明白可以看这篇文章

输出如下:

common acctact
jugg acctact
lina's life85
jugg's life90

火女只会调用父类的普通攻击,而剑圣则会调用自己的攻击方式,所以导致相同生命,相同攻击力,最终结果不同。


所以,虚函数可以理解为很多情况下, 子类都可以用父类的缺省值,但是也有一些例外的,对例外情况进行重写。


三 非虚函数 (即能实现接口,又能强制实现)

其实一般会认为非虚函数就是,子类中不用重写的函数,例如上文中的getLife等。如果需要重写的,最好写成虚函数,非虚函数的隐藏的方式其实效果不好,对于有些情况也不适用。

我之前的那篇文章中也说了非虚函数和虚函数的一些区别,如果想了解可以查看

http://blog.csdn.net/mlkiller/article/details/8852200  明明白白c++ 虚函数

它和上面的虚函数最大的区别就是虚函数是动态绑定。

也就是说只有一种情况是不一样的,当用父类指针和引用的时候,它会根据指针或者引用的真实内容是属于父类还是子类,来绑定对于的函数。

这里就不展开讲了,另外java里面也没有非虚函数这种形式。


那它存在有两个原因,我想,

第一是历史原因,因为c++源于c语言,可以单独的定义函数。

   大家是从c转换到c++都很容易接受这种函数形式,直接加virtual反而不容易接受。

第二是效率上会稍微有点提高。但是如果所有的函数都用虚函数其实也没有坏处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值