继承与派生
继承
面向对象程序设计4个主要特征:抽象,封装,继承,多态性
c++通过继承实现可重用性。有时两个类的内容基本相同或有一部分相同,这时可以利用原来声明的类作为基础,再加上新的内容即可,减少了工作量。

//比如有一个类
class student
{
public:
void display()
{cout<<"num:"<num<<endl;
cout<<"name"<<nam<<endl;
cout<<"sex"<<sex<<endl;
}
private:
int num;
string nam;
char sex;
};

现在想增加student 类的信息,可以重新写

 class student1
{
public:
void display()
{cout<<"num:"<num<<endl;
cout<<"name"<<nam<<endl;
cout<<"sex"<<sex<<endl;
cout<<"age"<<age<<endl;
cout<<"address"<<addr<<endl;
}
private:
int num;
string nam;
char sex;
int age;
char addr{}; };

也可以通过继承来实现

class student1: public student        //声明基类是student,
{
public:
void display() //新增加的成员函数
{cout<<"age"<<age<<endl;
cout<<"address"<<addr<<endl;}
private:
int age; //新增加的数据成员
char addr{}; //新增加的数据成员
};

声明派生类的一般形式

class 派生类名 :[继承方式] 基类名
{

 派生类新增加的成员;

};
 [继承方式]有 public(公用的)  , private(私有的) ,  protected(受保护的) ,如果不写,则默认为private。
 
派生类的构成过程:
  1. 从基类接收成员(派生类把基类全部成员[不包括构造函数,析构函数]接收过来)
  2. 调整从基类接收的成员(通过指定基类的继承方式来改变基类成员在派生类中访问属性)
  3. 在声明派生类时增加的成员
 
派生类成员的访问属性:
  1. public      基类的公有成员和保护成员  在派生类中保持原有的访问属性;私有成员仍为基类私有,只有基类的成员函数可以引用它,
        而不能被派生类的成员函数引用,因此就成为派生类中的不可访问的成员
  
  2.private        私有继承方式建立的派生类称为私有派生类,其基类称为私有基类
                        私有基类的公用成员和保护成员在派生类中访问属性相当于派生类中的私有成员,(派生类的成员函数能访问它们,而在派生类外不能访问它                                    们。)
                        私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们。
 
  3.protected     在保护继承方式建立的派生类称为保护派生类,其基类称为受保护的基类,简称保护基类。保护基类的公有成员和保护成员在派生类中变为                                   保护成员(不能被外界引用,但可以被派生类的成员函数访问),私有成员仍为基类私有。
 
对比私有派生类和保护派生类的访问属性,可以发现:
       在直接派生类中,这两种继承方式的作用实际上是相同的。(类外不能访问任何成员,而在派生类中可以通过成员函数访问基类中的公有成员和保护                  成员),但是如果继续继承派生,在新的派生类中两种继承方式的作用就不同了,例如对两种都进行公有继承,则私有派生类中的成员在新派生类中就不              能访问了,而保护派生类中的成员在新基类中仍为保护继承。
 
 
 
派生类的构造函数和析构函数
派生类的构造函数
因为基类的构造函数是不能继承的,所以在声明派生类时,派生类并没有把基类的构造函数继承过来,
因此,对继承过来的基类成员初始化的工作也要由派生类的构造函数承担。
思路:在执行派生类的构造函数时,调用基类的构造函数。
 
派生类构造函数一般形式:
派生类构造函数名 (总参数表):基类构造函数名(参数表)
 {派生类中新增数据成员初始化语句}
 
或者:
派生类构造函数名 (总参数表):基类构造函数名(参数表),...{}
 
 如:student1(int n, string nam, char s, int a) :student(n, nam, s),age(a){}
 
注意:
  派生类构造函数名后面的参数表中包括参数类型和参数名                         student1(int n, string nam, char s, int a)
  而基类构造函数名后面括号内的参数表只有参数名,而不包括类型名       student(n,nam,s)
  这是因为这里不是定义基类构造函数,而是对基类函数进行调用,这些参数是实参而不是形参。(类似函数的调用)
  在建立一个对象时,执行构造函数的顺序是,
   1.派生类先调用基类构造函数,
         2.执行派生类构造函数本身
 
 
 
 
有子对象的派生类的构造函数
类中的数据成员可以是标准类型(int,char ),系统提供的类型(string),还可以包含类对象
class student
{....
};
class student1
{
 int num;
 student monitor;       //定义子对象
};
上面中的对象monitor 就是类student1的子对象。
数据成员初始化时如何对子对象初始化?

#include<iostream>
#include<string>
using namespace std;
class student //基类
{
public:
student(string nam) //定义基类构造函数
{
name = nam;
}
~student() {} //基类的虚构函数
void display()
{
cout << "the name is:" << name << endl;
}
protected:
string name;
};
class student1 : public student //公共派生类
{
public:
student1(string nam,string nam1 ,int a) :student(nam),monitor(nam1) /*派生类构造函数,子对象的初始化是在建立派生类时通
                                          过调用派生类构造函数来实现的*/

{
age = a;
}
void display1() //新增加的成员函数
{
display();
cout << "age:" << age << endl;
} void show_monitor()
{
cout<<"class monior is :"<<endl;
monitor.display();
}
private:
int age; //新增加的数据成员
student monitor;
};
int main()
{
student1 stud("A171", "li", );
stud.display1();
return ;
}

以上派生类构造函数实现了

  1.对基类数据成员初始化
  2.对子对象数据成员初始化
  3.对派生类数据成员初始化
 
 
 
多重派生时的构造函数

class A
{
A(int a,int b,int c);
};
class B:public A
{
B(int a,int b,int c,int d ):A(a,b,c)
{
dive=d;
}
...
};
class C:public B
{
C(int a,int b,int c,int d,int e):B(a,b,c,d)
{
exchange=e;
} };

不要列出每一层派生类的构造函数,只需写出其上一层派生类的构造函数即可

 
 
 
派生类构造函数的特殊形式
1.当不需要对派生类新增的成员进行任何初始化操作时,派生类构造函数的函数体可以为空
          student1(string nam,string nam1 ) :student(nam),monitor(nam1){}
  此时派生类的构造函数的全部参数都传递给基类构造函数和子对象
2.如在基类中没有定义构造函数或定义了没有参数的构造函数,那么在定义派生类构造函数时可以不写基类构造函数
 
 
派生类的析构函数
在派生时,派生类是不能继承基类的析构函数的,也就需要通过派生类的析构函数去调用基类的析构函数。
派生类的析构函数对增加的成员进行清理工作,基类的清理工作仍然由基类的析构函数负责。
在执行派生类的析构函数时,系统会自动调用基类的析构函数和子对象的析构函数,对基类和子类进行清理。
 
 
 
多重继承
一个派生类中有两个或多个基类,派生类从两个或多个基类中继承所需的属性
声明多重继承的方法
class D :public A,public B,public C
{类D是新增的成员}
 
 
多重继承派生类的构造函数
与单继承形式基本相同,只是在初始化表中包含多个基类构造函数
派生类构造函数名(总参数表):基类1 构造函数(参数表),基类2 构造函数(参数表)...
{派生类中新增数据成员初始化语句}
多重继承引起的二义性问题
class A
{
public:
int a;
void display(); };
class B
{
public:
int a;
void display(); };
class C :public:A,public:B
{
public:
int b;
void show();
};
(为了简化,。没有写函数的定义)
int main()
{
C c1;
c1.a=; //出错,编译器无法判别要访问的是哪个基类的a,
c1.dispaly(); //出错,编译器无法判别要访问的是哪个基类的display()
c1.A::a=; //正确,使用基类名A来限定
}
如果类A和类B是从同一个基类派生的

class N
{
public:
int a;
void display(){
cout<<"A::a"<<a<<endl;
}
};
class A
{
public:
int a1;
void display(); };
class B
{
public:
int a2;
void display(); };
class C :public:A,public:B
{
public:
int a3;
void show(){
cout<<"a3="<<a3<<endl;
}
};
int main()
{
C c1;
...
}
如何访问类A中从基类N继承下来的成员呢
c1.a       //不行
c1.N::a    //不行
以上两者均不能区别是类A从基类N继承的成员,还是类B从基类继承的成员
c1.A::a=3  //可行
 
 
虚基类
如果一个派生类有多个直接基类,而这些直接基类都有同一个共同基类,则最终会在派生类中保留该间接共同基类数据成员的多份同名成员。
c++提供虚基类的方法,使在继承间接共同基类时只保留一份成员
class A
{...
};
class B: virtual public A
{...
};
class c:  virtual public A
{...
};
虚基类的初始化

class A
{A(int i){} //虚基类构造函数,有一个参数
};
class B: virtual public A
{B(int i):A(i){} //在初始化表对虚基类初始化
};
class c: virtual public A
{ c (int i):A(i){}
};
class d: public B,public c
{
d(int i):A(i),B(i),c(i){} //对初始化表中所有基类初始化 };

规定:在最后的派生类中不仅要负责对直接基类初始化,还要对虚基类初始化

c++语法笔记(中)的更多相关文章

  1. SQL基础语法笔记教程整理

    PS:本文适用SQL Server2008语法. 一.关系型数据库和SQL 实际上准确的讲,SQL是一门语言,而不是一个数据库. 什么是SQL呢?简而言之,SQL就是维护和使用关系型数据库中的的数据的 ...

  2. C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

    原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...

  3. 在为知笔记中使用Markdown和思维导图

    为知笔记Wiz是一款很好的网摘和笔记工具,作为为知的忠实用户,我在为知收费后第一时间就购买了两年的授权,毕竟这么多年积累的资料都在为知上,我也习惯了使用Wiz来做些工作相关的笔记.为知笔记自带Mark ...

  4. 菜鸟教程之学习Shell script笔记(中)

    菜鸟教程Shell script学习笔记(中) 以下内容是学习菜鸟教程之shell教程,所整理的笔记 菜鸟教程之shell教程:http://www.runoob.com/linux/linux-sh ...

  5. SQL 基础语法笔记教程整理

    最近从图书馆借了本介绍 SQL 的书,打算复习一下基本语法,记录一下笔记,整理一下思路,以备日后复习之用. PS:本文适用 SQL Server2008 语法. 首先,附一个发现的 MySQL 读书笔 ...

  6. [python] Pythonic语法笔记

    Pythonic语法笔记 __new__ 在类实例化之前执行的,也就是在init之前执行,可以为这个类写操作.接受的参数不是self而是cls.只有在new方法里返回类才会执行init操作,需要返回父 ...

  7. pyqt样式表语法笔记(中)--原创

    pyqt样式表语法笔记(中) pyqt QSS python 样式表 一.弹窗 在日常的各种桌面软件的使用中,我们都会碰到弹窗.例如注册,登录的时候,会有相应的信息弹窗,这里就以信息收集弹窗为例进行弹 ...

  8. pyqt样式表语法笔记(中)

    pyqt样式表语法笔记(中) pyqt QSS python 样式表 一.弹窗 在日常的各种桌面软件的使用中,我们都会碰到弹窗.例如注册,登录的时候,会有相应的信息弹窗,这里就以信息收集弹窗为例进行弹 ...

  9. Zookeeper学习笔记(中)

    Zookeeper学习笔记(中) Zookeeper的基本原理和基本实现 深入了解ZK的基本原理 ZK的一致性: ZAB 协议: Zookeeper 原子消息广播协议 ZK通过选举保证 leader ...

  10. C++ //多继承语法 C++中允许一个类继承多个类

    1 //多继承语法 C++中允许一个类继承多个类 2 #include <iostream> 3 #include <string> 4 using namespace std ...

随机推荐

  1. Linux下 为什么有时候使用sudo也提示没有权限

    例如: #sudo echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6 bash: /proc/sys/net/ipv6/conf/all/dis ...

  2. C语言应用--数据类型定制一结构体数组

    结构体定义成功后,其实和c语言内部的类型区别也不大了,自然可以用来定义结构体类型的数组了.我们根据结构体定义的方式不同,分别用多种方式定义结构体数组:

  3. 说自己熟悉 Spring Cloud 这些面试题你会吗

    问题一:什么是Spring Cloud? Spring cloud流应用程序启动器是基于Spring Boot的Spring集成应用程序,提供与外部系统的集成.Spring cloud Task,一个 ...

  4. Windows下的apache maven安装与配置

    去到官网http://maven.apache.org/download.cgi下载压缩包我选择的是二进制zip压缩文件. 解压并配置压缩文件的目录到MAVEN_HOME环境变量,添加解压文件下的bi ...

  5. scanf和fgets比较

    scanf 长度限制 #include<stdio.h> int main() { char food[5]; printf("Enter food"); scanf( ...

  6. Fiddler自动响应AutoResponder正则匹配

    AutoResponder-Add-Rule Editor 两个文本框,先说第一个: Mathes: 前缀为“EXACT:”表示完全匹配(大小写敏感) 无前缀表示基本搜索,表示搜索到字符串就匹配 前缀 ...

  7. 使用Flask构建机器学习模型API

    1. Python环境设置和Flask基础 使用"Anaconda"创建一个虚拟环境.如果你需要在Python中创建你的工作流程,并将依赖项分离出来,或者共享环境设置," ...

  8. linux redis 设置密码:

    在服务器上,这里以linux服务器为例,为redis配置密码. 1.第一种方式 (当前这种linux配置redis密码的方法是一种临时的,如果redis重启之后密码就会失效,) (1)首先进入redi ...

  9. [Java复习] MQ

    1. 为什么要用MQ? 解耦,异步,削峰 2. MQ的优点和缺点? 优点: 解耦.异步.削峰 缺点: 1. 系统可用性降低. 外部依赖越多,越容易挂.如果MQ挂了,怎么处理? 2. 系统复杂度提高. ...

  10. MySQL之二进制日志

    一.Binlog日志格式 根据日志定义的格式不一样,可以分为Statement格式.Row格式或者MIXED格式 mysql5.6----> | binlog_format | STATEMEN ...