继承


title: c++之继承
tags:


继承

C++派生语法

class Base
{
// ... base class members
};
class Derived: access-specifier Base
{
// ... derived class members
};
其中 access-specifier 可以是 public(这是最常见的,表示派生类是一个基类)、private 或 protected

下面是一个简单的历程,用来加深对继承的理解。

鱼类世界呈现的一种简单的继承层次结构

 #include <iostream> 
using namespace std; 
class Fish 
{ 
public: 
bool isFreshWaterFish; 
void Swim() 
{ 
if (isFreshWaterFish) 
cout << "Swims in lake" << endl; 
else 
cout << "Swims in sea" << endl; 
} 
}; 

class Tuna: public Fish 
{ 
public: 
Tuna() 
{ 
isFreshWaterFish = false;
} 
}; 

class Carp: public Fish 
{ 
public: 
Carp() 
{ 
isFreshWaterFish = true; 
} 
}; 

int main() 
{ 
Carp myLunch; 
Tuna myDinner; 

cout << "About my food:" << endl; 

cout << "Lunch: "; 
myLunch.Swim(); 

cout << "Dinner: "; 
myDinner.Swim(); 

return 0; 
} 
输出:
About my food: 
Lunch: Swims in lake 
Dinner: Swims in sea

访问限定符 protected

public 和 private 一样,protected 也是一个访问限定符。将属性声明为 protected 的时,
相当于允许派生类和友元类访问它,但禁止在继承层次结构外部(包括 main( ))访问它.

一种更好的 Fish 类设计,它使用关键字 protected 将成员属性只暴露给派生类
#include <iostream> 
 using namespace std; 

class Fish 
   { 
    protected: 
       bool isFreshWaterFish;  
    public: 
         void Swim() 
   { 
      if (isFreshWaterFish) 
     cout << "Swims in lake" << endl; 
   else 
      cout << "Swims in sea" << endl; 
 } 
    }; 

 class Tuna: public Fish
  { 
public: 
    Tuna() 
      { 
 isFreshWaterFish = false; // set protected member in base 
     }
  }; 

class Carp: public Fish 
 { 
public: 
    Carp() 
   { 
  isFreshWaterFish = false; 
   } 
 }; 

int main() 
{
 Carp myLunch; 
 Tuna myDinner; 
 cout << "About my food" << endl;  
 cout << "Lunch: "; 
 myLunch.Swim();  
 cout << "Dinner: "; 
 myDinner.Swim(); 
 return 0; 
    } 
}

输出:
About my food 
Lunch: Swims in lake 
Dinner: Swims in sea 


## 基类初始化—向基类传递参数
 结构如下:
class Base 
{ 
public: 
 Base(int someNumber) // overloaded constructor 
 { 
 // Use someNumber 
 } 
}; 
Class Derived: public Base 
{ 
public: 
 Derived(): Base(25) // instantiate Base with argument 25 
 { 
 // derived class constructor code 
 } 
}; 

下面看一下具体例子;

#include <iostream> 
  using namespace std;  
 class Fish 
     { 
  protected: 
           bool isFreshWaterFish; // accessible only to derived classes 
 public: 
          Fish(bool isFreshWater) : isFreshWaterFish(isFreshWater)
         {
         } 
 void Swim() 
     { 
      if (isFreshWaterFish) 
         cout << "Swims in lake" << endl; 
   else 
         cout << "Swims in sea" << endl; 
    } 
  }; 

class Tuna: public Fish 
 { 
 public: 
        Tuna(): Fish(false) 
          {
           }
 }; 

class Carp: public Fish 
 { 
public: 
         Carp(): Fish(true)
          {
          } 
  }; 
 
 int main() 
 { 
       Carp myLunch; 
       Tuna myDinner; 
 cout << "About my food" << endl; 
cout << "Lunch: "; 
 myLunch.Swim(); 
cout << "Dinner: "; 
myDinner.Swim(); 
 return 0; 
} 

输出:
About my food 
Lunch: Swims in lake 
Dinner: Swims in sea

在派生类中覆盖基类的方法

如果派生类实现了从基类继承的函数,且返回值和特征标相同,就相当于覆盖了基类的这个方法,
如下面的代码所示:
class Base
{
public:
void DoSomething()
{
// implementation code… Does something
}
};
class Derived:public Base
{
public:
void DoSomething()
{
// implementation code… Does something else
}
};

派生类 Tuna 和 Carp 覆盖了基类 Fish 的方法 Swim( ) 
 #include <iostream> 
using namespace std; 

class Fish 
        { 
private: 
        bool isFreshWaterFish; 
 public: 
        Fish(bool isFreshWater) 
         : isFreshWaterFish(isFreshWater)
          {
          } 
 void Swim() 
 { 
if (isFreshWaterFish) 
 cout << "Swims in lake" << endl; 
       else 
 cout << "Swims in sea" << endl; 
 } 
          }; 

 class Tuna: public Fish 
 { 
public: 
       Tuna()
         : Fish(false) 
{
} 
 void Swim() 
{ 
 cout << "Tuna swims real fast" << endl; 
   } 
    }; 

 class Carp: public Fish 
{ 
 public: 
        Carp()
              : Fish(true)
              {
              } 
 void Swim() 
  { 
      cout << "Carp swims real slow" << endl; 
   } 
 }; 

int main() 
 { 
Carp myLunch; 
Tuna myDinner; 
cout << "About my food" << endl; 
cout << "Lunch: "; 
myLunch.Swim(); 
cout << "Dinner: "; 
 myDinner.Swim(); 
return 0; 
 } 

输出:
About my food 
Lunch: Carp swims real slow 
Dinner: Tuna swims real fast 

分析: myLunch.Swim( )调用的是 Carp::Swim( )。同样,myDinner.Swim( )调用的是Tuna::Swim( )。换句话说,基类 Fish 中 Swim( )被派生类 Tuna 和 Carp 类中的 Swim( )覆盖了。要调用 Fish::Swim( ),只能在 main( )中使用作用域解析运算符显式地调用它。
即:如果要在 main( )中调用 Fish::Swim( ),需要使用作用域解析运算符(::),如
下所示:
myDinner.Fish::Swim();

在派生类中调用基类的方法

如果要在 Tuna::Swim( )
和 Carp::Swim( )的实现中重用 Fish::Swim( )的通用实现,可使用作用域解析运算符(::),如下面的代
码所示:
class Carp: public Fish
{
public:
Carp(): Fish(true) {}
void Swim()
{
cout << "Carp swims real slow" << endl;
Fish::Swim(); // invoke base class function using operator::
}
};

具体应用

在基类方法和 main( )中,使用作用域解析运算符(::)来调用基类方法

 #include <iostream> 
using namespace std; 
 class Fish 
{ 
 private: 
 bool isFreshWaterFish;  
public: 
 Fish(bool isFreshWater) : isFreshWaterFish(isFreshWater){} 
void Swim() 
{ 
 if (isFreshWaterFish) 
 cout << "Swims in lake" << endl; 
 else 
cout << "Swims in sea" << endl; 
 } 
 }; 
 class Tuna: public Fish 
 { 
 public: 
 Tuna(): Fish(false) {} 
 void Swim() 
 { 
 cout << "Tuna swims real fast" << endl; 
 } 
 }; 
 class Carp: public Fish 
 { 
 public: 
 Carp(): Fish(true) {} 
 void Swim() 
 { 
 cout << "Carp swims real slow" << endl; 
Fish::Swim(); 
 } 
 }; 
 int main() 
 { 
Carp myLunch; 
 Tuna myDinner; 
 cout << "About my food" << endl;  
 cout << "Lunch: "; 
 myLunch.Swim(); 
 cout << "Dinner: "; 
 myDinner.Fish::Swim(); 
 return 0; 
 } 
输出:
About my food 
Lunch: Carp swims real slow 
Swims in lake 
Dinner: Swims in sea 

构造顺序

基类对象在派生类对象之前被实例化。首先构造 Tuna 对象的Fish 部分,这样实例化 Tuna 部分时,成员属性(具体地说是 Fish 的保护和公有属性)已准备就绪,可以使用了。实例化 Fish 部分和 Tuna 部分时,先实例化成员属性(如 Fish::isFreshWaterFish),再调用构造函数,确保成员属性准备就绪,可供构造函数使用。这也适用于 Tuna::Tuna( )。
析构顺序与此相反

私有继承

格式如下:
class Base
{
// ... base class members and methods
};
class Derived: private Base // private inheritance
{
// ... derived class members and methods
};

私有继承意味着在派生类的实例中,基类的所有公有成员和方法都是私有的—不能从外部访问。
换句话说,即便是 Base 类的公有成员和方法,也只能被 Derived 类使用,而无法通过 Derived 实例来
使用它们。
在公有继承中,,可在 main( )中通过 Tuna 实例调用 Fish::Swim( ),因为 Fish::Swim( )是个公有方法,且 Tuna 类是以公有方式从 Fish 类派生而来的。而在私有继承中无法实现。私有继承使得只有子类才能使用基类的属性和方法,因此也被称为 has-a 关系。
比如由发动机派生汽车,由小到大的派生。

实例

Car 类以私有方式继承 Motor 类
 0: #include <iostream> 
 using namespace std; 
 class Motor 
 { 
 public: 
 void SwitchIgnition() 
   { 
 cout << "Ignition ON" << endl; 
  } 
 void PumpFuel() 
   { 
 cout << "Fuel in cylinders" << endl; 
   } 
 void FireCylinders() 
 { 
 cout << "Vroooom" << endl; 
 } 
           };  

class Car:private Motor // private inheritance 
 { 
 public: 
 void Move() 
{ 
   SwitchIgnition(); 
   PumpFuel(); 
   FireCylinders(); 
    } 
           }; 

 int main() 
 { 
    Car myDreamCar; 
    myDreamCar.Move(); 
 return 0; 
 } 

输出:
Ignition ON 
Fuel in cylinders 
Vroooom 

保护继承

结构如下:
class Base
{
// ... base class members and methods
};
class Derived: protected Base // protected inheritance
{
// ... derived class members and methods
};
特征:
• 它也表示 has-a 关系;
• 它也让派生类能够访问基类的所有公有和保护成员;
• 在继承层次结构外面,也不能通过派生类实例访问基类的公有成员。
随着继承层次结构的加深,保护继承将与私有继承有些不同:
class Derived2: protected Derived
{
// can access public & protected members of Base
}
在保护继承层次结构中,子类的子类(即 Derived2)能够访问 Base 类的公有和保护成员

实例理解

 RaceCar 类以保护方式继承了 Car 类,而 Car 类以保护方式继承了 Motor 类
#include <iostream> 
 using namespace std; 
 class Motor 
 { 
 public: 
 void SwitchIgnition() 
 { 
 cout << "Ignition ON" << endl; 
 } 
void PumpFuel() 
 { 
 cout << "Fuel in cylinders" << endl; 
 } 
void FireCylinders() 
 { 
cout << "Vroooom" << endl; 
 } 
 }; 
 class Car:protected Motor 
{ 
public: 
 void Move() 
 { 
 SwitchIgnition(); 
PumpFuel(); 
FireCylinders(); 
 } 
 };  
class RaceCar:protected Car 
 { 
public: 
 void Move() 
 { 
SwitchIgnition(); 
 PumpFuel(); 
 FireCylinders();
 FireCylinders(); 
 FireCylinders(); 
 } 
 }; 
 int main() 
 { 
 RaceCar myDreamCar;
 myDreamCar.Move();  
return 0; 
 } 

输出:
Ignition ON 
Fuel in cylinders 
Vroooom 
Vroooom 
Vroooom 

多继承

class Derived: access-specifier Base1, access-specifier Base2
{
// class members
};

使用 final 禁止继承

被声明为 final 的类不能用作基类。


文章依据21天学通C++第八版,纯属小白自学!!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • 一、基类或父类 派生类或子类 1、继承方式有三种:public private protected 默认的是pri...
    割麦子洁阅读 611评论 0 0
  • 1. 语法 原则:is-a父类/子类基类/派生类 语法 如果不写继承访问限定符,默认是private 实例:图形继...
    jdzhangxin阅读 1,213评论 0 7
  • 派生类访问权限 派生类对象的体积 = 基类对象的体积 +派生类对象自己的成员变量的体积 ,派生类对象包含着基类对象...
    zhouluyao阅读 411评论 0 0
  • 一个月来,由于点赞也可以得钻,我就留恋于各位朋友粉丝们的空间,没事儿看看,随手点个赞。 本想着混些人气,可是发现,...
    牵着蜗牛狂奔阅读 303评论 0 3
  • 一只鸟的鸣叫 一株草的生长 叫醒了我 清新是朝阳的光芒 油条豆浆是生活的芬芳 面对太阳我从不低下头 因为我知道人生...
    河汉阅读 210评论 0 0