C++因继承引发的隐藏与重写

在区分隐藏重写之前,先来理一理关于继承的东西。。。

继承

继承是面向对象复用的重要手段。通过继承定义一个类,继承是类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。简单的说,继承就是指一个对象直接使用另一对象的属性和方法。C++中的继承关系就好比现实生活中的父子关系,继承一套房子通常比白手起家自己挣要容易得多。所以原始类被称为父类或基类,继承类称为子类或派生类,而子类又可以当成父类,可再被其它类继承。这种关系和java是一样道理,不过C++多了一个麻烦的地方就是它还支持多继承,于是就引发出很多坑人的地方。

继承的方式:
(1) 公有继承(public)

  基类的公有和保护成员被子类继承时,它们都保持原有的状态,而基类的私有成员同样被继承下来,只是在子类表现为私有,子类不能访问。

(2)私有继承(private)

  它的特点是基类的公有和保护成员被子类继承时,都会成为子类的私有成员;基类的私有成员也被继承下来,但不能被该子类访问。

(3)保护继承(protected)

  它的特点是基类的公有成员和保护成员被子类继承时,都会成为子类的保护成员,子类的子类可通过保护成员函数或友元访问;基类的私有成员被继承下来仍然是私有的,依旧不能被子类访问。

private能够对外部和子类保密,即除了成员所在的类本身可以访问之外,别的都不能直接访问。protected能够对外部保密,但允许子类直接访问这些成员。不难看出protected限定符是因为继承才能表现出作用

各种继承方式下各种成员关系变化如下图

C++因继承引发的隐藏与重写

承方式就像一张‘网’,被继承后都成了跟‘网’权限“相同的”和比“网” ’“小”的。

总结一下:
  1. public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
  2. protetced/private继承是一个实现继承,基类的部分成员并未完全成为子类接口的一部分,是 has-a 的关系原则,所以非特殊情况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。
  3. 不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,但是基类的私有成员存在但是在子类中不可见(不能
访问)。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。

赋值兼容规则

 要点:

  1. 子类对象可以赋值给父类对象(支持对象切片)   
  2. 父类对象不能赋值给子类对象
  3. 父类的指针/引用可以指向子类对象 
  4. 子类的指针/引用不能指向父类对象(可通过强制类型转换完成)

例子:

1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Person 6 { 7 public: 8 void Show() 9 { 10 cout<<_name<<endl; 11 } 12 protected: 13 string _name; 14 }; 15 16 struct Student : public Person 17 { 18 public: 19 void Print() 20 { 21 cout<<_name<<endl; 22 } 23 24 //private: 25 public: 26 string _id; 27 }; 28 29 void test1() 30 { 31 Person p; 32 Student s; 33 34 p = s; // 不是隐式类型转换 -- 切片处理-编译器天然支持 -- is-a 35 Person* pP = &s; //通过 36 Person& p1 = s; //通过 37           //上面都属于一种向上类型的转换,编译器默认支持。 38 //s = p; //报错,类型不匹配 39 Student* p3 = (Student*)&p; //编译通过,通过p3进行操作会出错 40 //p3->_id = 10; //该句执行完虽给p3->_id赋了值,但在整个程序结束时程序会崩掉,因为强转为了子类的指针,那么编译器就会按子类 41         //的大小对该指针作解释,这样就多‘占用’一块内存,而它可能是用来执行其他的活动的,但p3->id却指向这块非法的内存。 42 Student& r3 = (Student&)p; //编译通过,用r3进行操作出错 43 //Student& r3 = p; //出错 44 //r3._id = 10; //运行出错,同上面道理 45 46 }

注:p = s操作时会将子类对象独有的(非继承的部分)函数和变量自动“切去”,子类只留下继承来的基类原有的“切片”来对基类的对象进行赋值。         

      

C++因继承引发的隐藏与重写

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppygw.html