c++ inheritance -- 继承

终于要决心弄明白继承了,以前仅限于大学时学习,以后工作也没有用,现在就依照(百度百科)文章写些测试的代码。

文章说
=============================
C++继承  在C++语言中,一个派生类可以从一个基类派生,也可以从多个基类派生。从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。   派生类的定义格式   单继承的定义格式如下:   class <派生类名>:<继承方式><基类名>   {   <派生类新定义成员>   };   其中,<派生类名>是新定义的一个类的名字,它是从<基类名>中派生的,并且按指定的<继承方式>派生的。<继承方式>常使用如下三种关键字给予表示:   public 表示公有基类;   private 表示私有基类;   protected 表示保护基类;   多继承的定义格式如下:   class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…   {   <派生类新定义成员>   };   可见,多继承与单继承的区别从定义格式上看,主要是多继承的基类多于一个。   如果省略继承方式,对'class'将采用私有继承,对'struct'将采用公有继承。   也就是说   class Base1{};   struct Base2{};   class Derive:Base1,Base2{};   那么,Derive类将私有继承Base1,公有继承Base2。相当于:   class Derive:private Base1,public Base2{};派生类的三种继承方式  公有继承(public)、私有继承(private)、保护继承(protected)是常用的三种继承方式。   1. 公有继承(public)   公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。   2. 私有继承(private)   私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。   3. 保护继承(protected)   保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。   下面列出三种不同的继承方式的基类特性和派生类特性。   

  public protected private
公有继承 public protected 不可见
私有继承 private private 不可见
保护继承 protected protected 不可见

  为了进一步理解三种不同的继承方式在其成员的可见性方面的区别,下面从三种不同角度进行讨论。对于公有继承方式  (1) 基类成员对其对象的可见性:   公有成员可见,其他不可见。这里保护成员同于私有成员。   (2) 基类成员对派生类的可见性:   公有成员和保护成员可见,而私有成员不可见。这里保护成员同于公有成员。   (3) 基类成员对派生类对象的可见性:   公有成员可见,其他成员不可见。   所以,在公有继承时,派生类的对象可以访问基类中的公有成员;派生类的成员函数可以访问基类中的公有成员和保护成员。这里,一定要区分清楚派生类的对象和派生类中的成员函数对基类的访问是不同的。对于私有继承方式  (1) 基类成员对其对象的可见性:   公有成员可见,其他成员不可见。   (2) 基类成员对派生类的可见性:   公有成员和保护成员是可见的,而私有成员是不可见的。   (3) 基类成员对派生类对象的可见性:   所有成员都是不可见的。   所以,在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。对于保护继承方式  这种继承方式与私有继承方式的情况相同。两者的区别仅在于对派生类的成员而言,对基类成员有不同的可见性。   上述所说的可见性也就是可访问性。关于可访问性还有另的一种说法。这种规则中,称派生类的对象对基类访问为水平访问,称派生类的派生类对基类的访问为垂直访问。一般规则  公有继承时,水平访问和垂直访问对基类中的公有成员不受限制;   私有继承时,水平访问和垂直访问对基类中的公有成员也不能访问;   保护继承时,对于垂直访问同于公有继承,对于水平访问同于私有继承。   对于基类中的私有成员,只能被基类中的成员函数和友元函数所访问,不能被其他的函数访问。   基类与派生类的关系   任何一个类都可以派生出一个新类,派生类也可以再派生出新类,因此,基类和派生类是相对而言的。基类与派生类之间的关系1. 派生类是基类的具体化  类的层次通常反映了客观世界中某种真实的模型。在这种情况下,不难看出:基类是对若干个派生类的抽象,而派生类是基类的具体化。基类抽取了它的派生类的公共特征,而派生类通过增加行为将抽象类变为某种有用的类型。2. 派生类是基类定义的延续  先定义一个抽象基类,该基类中有些操作并未实现。然后定义非抽象的派生类,实现抽象基类中定义的操作。例如,虚函数就属此类情况。这时,派生类是抽象的基类的实现,即可看成是基类定义的延续。这也是派生类的一种常用方法。3. 派生类是基类的组合  在多继承时,一个派生类有多于一个的基类,这时派生类将是所有基类行为的组合。   派生类将其本身与基类区别开来的方法是添加数据成员和成员函数。因此,继承的机制将使得在创建新类时,只需说明新类与已有类的区别,从而大量原有的程序代码都可以复用,所以有人称类是“可复用的软件构件”。继承成员的调整1.恢复访问控制方式  访问声明采用作用域"::" ,它的一般形式为:基类名::成员名;。在派生类的类界面中,将这些访问声明放在合适的访问控制保留字之后,从而改变在派生类中该成员的访问控制方式。2.继承成员的重定义  如果在派生类中定义了一个函数原型与继承成员函数一模一样的成员函数,则该函数实现的函数体是对继承成员函数的重定义。

=============================
代码
  1. #include <iostream>
  2. #include <cstring>
  3. #include <string>
  4. using namespace std;
  5. enum e_zoo_obj_kind{
  6. null = 0,
  7. #define zk_null (e_zoo_obj_kind(null))
  8. no = 0,
  9. #define zk_no (e_zoo_obj_kind(no))
  10. animal = 1,
  11. #define zk_animal (e_zoo_obj_kind(animal))
  12. plant = 2,
  13. #define zk_plant (e_zoo_obj_kind(plant))
  14. others = 3,
  15. #define zk_others (e_zoo_obj_kind(others))
  16. max = 4
  17. #define zk_max 4
  18. };
  19. static const char * g_zk_str [zk_max ] ={
  20. "null",
  21. "animal",
  22. "plant",
  23. "others"
  24. };
  25. #define NEW_LINE std::cout<<"\n"
  26. static unsigned int g_msg_id = 0;
  27. enum e_msg_type{
  28. mt_fatal = 0, //0
  29. mt_notice,
  30. mt_debug,
  31. mt_info ,
  32. mt_ignore, // 4
  33. mt_max // 5
  34. #define MSG_TYPE_MAX 5
  35. };
  36. static const char *g_msg_type_str[MSG_TYPE_MAX] = {
  37. "FATAL",
  38. "NOTICE",
  39. "DEBUG",
  40. "INFO",
  41. "IGNORE"
  42. };
  43. class Message{
  44. private:
  45. unsigned int id;
  46. protected:
  47. e_msg_type type;
  48. public:
  49. string msg;
  50. public:
  51. Message():id(++g_msg_id),type(mt_ignore),msg("null"){}
  52. Message(e_msg_type t, string m):type(t),msg(m),id(++g_msg_id){}
  53. Message &set_type(e_msg_type t){ type = t; return *this; }
  54. e_msg_type get_type(){ return type; }
  55. Message &set_msg(string m){msg = m; return *this; }
  56. Message &print(void){
  57. cout << "Msg:"
  58. << "id-" << id
  59. << ",type-" << g_msg_type_str[type]
  60. << ",msg-" << msg << endl;
  61. return *this;
  62. }
  63. };
  64. class Obj{
  65. private:
  66. char name [40];
  67. public:
  68. Obj() { strcpy(name,"null") ;}
  69. Obj(char *nm){
  70. strncpy(name,!nm?"null":nm,sizeof(name));
  71. }
  72. void say(){
  73. cout << "name:" << name << endl;
  74. }
  75. void say(Obj *obj){
  76. !obj
  77. ? cout << "null\n"
  78. : cout << "name:" << obj->name << endl;
  79. }
  80. void set_name(char *nm){
  81. !nm ?"": strncpy(name,nm,sizeof(name));
  82. }
  83. char *get_name(void) {return name;}
  84. };
  85. class Zoo_obj:public Obj{
  86. private:
  87. e_zoo_obj_kind kind;
  88. public:
  89. Zoo_obj():Obj(),kind(null) {}
  90. Zoo_obj(char *nm, e_zoo_obj_kind k):Obj(nm),kind(k){
  91. }
  92. void say(void){
  93. cout << "Zoo_obj::";
  94. Obj::say();
  95. cout << "kind:" << g_zk_str[kind] << endl;
  96. }
  97. void say(Zoo_obj &obj){
  98. cout << "Zoo_obj::";
  99. Obj::say();
  100. cout << "kind:" << g_zk_str[obj.kind] << endl;
  101. }
  102. e_zoo_obj_kind get_kind(){ return kind; }
  103. Zoo_obj &set_kind(e_zoo_obj_kind k){
  104. kind = k;
  105. return *this;
  106. }
  107. Zoo_obj &print_kind(){
  108. cout << "kind:" << g_zk_str[kind] << endl;
  109. return *this;
  110. }
  111. };
  112. class Animal:public Zoo_obj{
  113. private:
  114. int lags;
  115. public:
  116. Animal(char *nm, int l) :lags(l),Zoo_obj(nm,animal){ }
  117. void say(){
  118. Obj::say();
  119. Zoo_obj::say();
  120. cout << "lag:" << lags << endl;
  121. }
  122. };
  123. class Plant:public Obj, protected Message{
  124. private:
  125. union {
  126. unsigned int property;
  127. struct{
  128. unsigned int
  129. hasleaf:1,
  130. hasflower:1,
  131. hastrunk:1,
  132. hasrattan:1,
  133. private1:1,
  134. private2:1;
  135. };
  136. };
  137. public:
  138. Plant():Obj(),property(0){ }
  139. Plant &set_leaf(bool has) {hasleaf = has; return *this;}
  140. Plant &set_flower(bool has) {hasflower = has; return *this;}
  141. Plant &set_trunk(bool has) {hastrunk = has; return *this;}
  142. Plant &set_rattan(bool has) {hasrattan = has; return *this;}
  143. bool has_leaf(){return hasleaf ;}
  144. bool has_flower(){return hasflower ;}
  145. bool has_trunk(){return hastrunk ;}
  146. bool has_rattan(){return hasrattan;}
  147. Plant & print(void){
  148. Obj::say();
  149. cout << "has leaf:" << hasleaf << endl;
  150. cout << "has flower:" << hasflower << endl;
  151. cout << "has trunk:" << hastrunk << endl;
  152. cout << "has rattan:" << hasrattan << endl;
  153. return *this;
  154. }
  155. };
  156. int main(void){
  157. Zoo_obj obj = Zoo_obj( "cat", e_zoo_obj_kind(animal));
  158. obj.say(); //inherit from Obj in public-style
  159. NEW_LINE;
  160. obj.print_kind().set_kind(no).print_kind(); //series invoking
  161. NEW_LINE;
  162. Plant peony;
  163. peony.set_name("peony"); // Obj::set_name()
  164. peony.set_leaf(true).set_flower(true).print();
  165. NEW_LINE;
  166. Animal dog ("joel's dog",4); // say by its father and grandfather
  167. dog.say();
  168. dog.set_name("black dog") ;
  169. /* Obj::set_name if Zoo_obj was
  170. described by protect, the assembler would show
  171. "error: ‘void Obj::set_name(char*)’ is inaccessible"
  172. */
  173. NEW_LINE;
  174. test_Mesaage:
  175. Message msg;
  176. msg.print();
  177. NEW_LINE;
  178. test_sizeof:
  179. cout << "sizeof these:"
  180. << "\nObj: " << sizeof(Obj)
  181. << "\nMessage: " << sizeof(Message)
  182. << "\nZoo_obj: " << sizeof(Zoo_obj) << "\t:Obj + enum"
  183. << "\nAnimal: " << sizeof(Animal) << "\t:Zoo_obj + int"
  184. << "\nPlant: " << sizeof(Plant) << "\t:Obj,Message + union\n";
  185. }
结果
  1. Zoo_obj::name:cat
  2. kind:animal
  3. kind:animal
  4. kind:null
  5. name:peony
  6. has leaf:1
  7. has flower:1
  8. has trunk:0
  9. has rattan:0
  10. name:joel's dog
  11. Zoo_obj::name:joel's dog
  12. kind:animal
  13. lag:4
  14. Msg:id-2,type-IGNORE,msg-null
  15. sizeof these:
  16. Obj: 40
  17. Message: 12
  18. Zoo_obj: 44 :Obj + enum
  19. Animal: 48 :Zoo_obj + int
  20. Plant: 56 :Obj,Message + union
从test_sizeof段中可以看出,一个类(eg. O)的大小会是他本身和他的祖先(A)大小的和,我真看不出这有什么好,假设他protected继承(P),他的子孙(S)就不能从他的祖先(P)中得到好处,除了徒增自身大小。
 
还有,用gdb调试可以清楚的看到,在继承时自身空间的排列,先是祖先的空间分配,接着是自身的成员。千万不能简单的在成员函数中像c一样初始化 
  1. memset(this,0,sizeof(class ONESEL));
这样真的就**了,我就犯了混,因为继承,使他隐藏的太深了。
这里没有涉及到友元函数,虚函数。
明天吧,在写点测试代码。
 

c++ inheritance -- 继承的更多相关文章

  1. 第五章 Inheritance继承

    [继承] Java不支持多重继承 - 每个子类只有一个超类. 不是将成员变量声明为静态,更好的做法是将University实例化为对象,然后使用该对象访问其成员,如下所示: [抽象类] 可以包含或者不 ...

  2. Python3学习之路~6.6 类的继承

    Inheritance 继承 面向对象编程 (OOP) 语言的一个主要功能就是“继承”.继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展.通过继承创 ...

  3. 逆袭之旅.DAY07东软实训..封装~继承~抽象~final

    2018年7月3日.逆袭之旅DAY07 package day0703.exam1; /** * 狗狗类 使用权限修饰符private和public进行封装 * @author Administrat ...

  4. lesson 4 再谈继承多态,抽象类和接口

    再谈多态,抽象类和接口 上一次博客已经概念性的概述了继承多态,抽象类和接口,这次来具体的谈一谈他们之间的联系和需要注意的地方. 一.继承和多态:Inheritance (继承) & Polym ...

  5. Day 18 :面向对象[基础,继承,组合]类的增删改查

    有的人说,编程有3种范式: 1.面向过程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了. 2.面向函数:面向函数是面向过程的升级版,也就是把每个 ...

  6. Hibernate继承注解

    hibernate应用中,继承的用途或目的主要有两点: 组件化:故明思义,把重复性的代码抽取成组件,以便重用和维护.hibernate应用中,一些重复的字段,重复的映射配置,就需要抽取成组件. 多态性 ...

  7. java中到底什么是继承?

    1.何为继承?What is Inheritance? 在上图中,对于车来讲,汽车就是子类.对于汽车来讲,奔驰就是子类.车是汽车的基类,超类,或说父类.到底什么是继承?马克-to-win,子类把父类的 ...

  8. Python之路,Day7 - Python基础7 面向对象

    本节内容:   面向对象编程介绍 为什么要用面向对象进行开发? 面向对象的特性:封装.继承.多态 类.方法.     引子 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战> ...

  9. UML类图的6大关系

    <小酌重构系列>已经完成了大约1/3了,在这些文章中,我使用了一些简单的类图来描述重构策略.在之后的文章中,我可能会借助稍微复杂一些的UML类图来介绍.但是在此之前,我觉得有必要先介绍一下 ...

随机推荐

  1. T-sql表表达式

    内联表值函数 可以理解是个带参数的视图的表达式,好处就是创建后,可永久保存在数据库中,查询复用. 创建的格式: create function 函数名 (参数名 as 参数类型) return tab ...

  2. C: 函数的名字是否受大小写影响?

    函数的名字大小写是否为同一函数? 不是,大小写不同,函数不同. 环境: gcc 版本 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) Linux ubuntu 3.2.0-2 ...

  3. 分享非常有用的Java程序 (关键代码) (一)

    原文:分享非常有用的Java程序 (关键代码) (一)   分享一些非常有用的Java程序 (关键代码) ,希望对你有所帮助. 1.  得到当前方法的名字 String methodName = Th ...

  4. WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化

    原文:WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化 [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制 ...

  5. perl encode_utf8必须用在utf8环境

    [root@wx03 mojo]# cat test.pl use Mojolicious::Lite; use JSON qw/encode_json decode_json/; use Encod ...

  6. HttpURLConnection中使用代理(Proxy)及其验证(Authentication)

    HttpURLConnection中使用代理(Proxy)及其验证(Authentication) 使用Java的HttpURLConnection类可以实现HttpClient的功能,而不需要依赖任 ...

  7. SQL中on条件与where条件的区别(转载)

    数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和where条件的区别如下: 1. on条件是在生成临时表时使用的条 ...

  8. 跟着鬼哥学so改动,一,准备篇

    图/文 听鬼哥说故事 闲话少说,so的改动,重要性大家都知道,这里从头编写so文件,分析so文件,改动so文件,打算做一个系列的教程,当然,主要是看时间同意. android的sdk配置以及ndk环境 ...

  9. java基本数据类型转换成byte[]数组

    import java.io.UnsupportedEncodingException;  public class ConToByte {      /**     * double转换byte   ...

  10. 基于visual Studio2013解决面试题之0601二叉树深度

     题目