详解C++编程中多级派生时的构造函数和访问属性

C++多层派生时的构造函数
一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构。在上面叙述的基础上,不难写出在多级派生情况下派生类的构造函数。

通过例下面的程序,读者可以了解在多级派生情况下怎样定义派生类的构造函数。相信大家完全可以自己看懂这个程序。

[例] 多级派生情况下派生类的构造函数。

#include <iostream>
#include<string>
using namespace std;
class Student//声明基类
{
public://公用部分
  Student(int n, string nam)//基类构造函数
  {
   num=n;
   name=nam;
  }
  void display( )//输出基类数据成员
  {
   cout<<"num:"<<num<<endl;
   cout<<"name:"<<name<<endl;
  }
protected://保护部分
  int num;//基类有两个数据成员
  string name;
};
class Student1: public Student//声明公用派生类Student1
{
public:
  Student1(int n,char nam[10],int a):Student(n,nam)//派生类构造函数
  {age=a;}//在此处只对派生类新增的数据成员初始化
  void show( ) //输出num,name和age
  {
   display( ); //输出num和name
   cout<<"age: "<<age<<endl;
  }
private://派生类的私有数据
  int age; //增加一个数据成员
};
class Student2:public Student1 //声明间接公用派生类Student2
{
public://下面是间接派生类构造函数
  Student2(int n, string nam,int a,int s):Student1(n,nam,a) {score=s;}
  void show_all( ) //输出全部数据成员
  {
   show( ); //输出num和name
   cout<<"score:"<<score<<endl; //输出age
  }
private:
  int score; //增加一个数据成员
};
int main( )
{
  Student2 stud(10010,"Li",17,89);
  stud.show_all( ); //输出学生的全部数据
  return 0;
}

运行时的输出如下:

num:10010
name:Li
age:17
score:89

请注意基类和两个派生类的构造函数的写法。

基类的构造函数首部:

  Student(int n, string nam)

派生类Student1的构造函数首部:

  Student1(int n, string nam],int a):Student(n,nam)

派生类Student2的构造函数首部:

  Student2(int n, string nam,int a,int s):Student1(n,nam,a)

注意不要写成:

  Student2(int n, string nam,int a,int s):Student1(n,nam),student1(n, nam, a)

不要列出每一层派生类的构造函数,只需写出其上一层派生类(即它的直接基类)的构造函数即可。在声明Student2类对象时,调用Student2构造函数;在执行Student2构造函数时,先调用Student1构造函数;在执行Student1构造函数时,先调用基类Student构造函数。初始化的顺序是:
先初始化基类的数据成员num和name。
再初始化Student1的数据成员age。
最后再初始化Student2的数据成员score。

C++类多级派生时的访问属性
在实际项目开发中,经常会有多级派生的情况。如图11.9所示的派生关系:类A为基类,类B是类A 的派生类,类C是类B的派生类,则类C也是类A的派生类;类B称为类A 的直接派生类,类C称为类A的间接派生类;类A是类B的直接基类,是类 C的间接基类。

在多级派生的情况下,各成员的访问属性仍按以上原则确定。

为了把多重继承说的更加详细,请大家先看下面的几个继承的类。

[例] 如果声明了以下的类:

class A //基类
{
public:
  int i;
protected:
  void f2( );
  int j;
private:
  int k;
};
class B: public A //public方式
{
public:
  void f3( );
protected:
  void f4( );
private:
  int m;
};
class C: protected B //protected方式
{
public:
  void f5( );
private:
  int n;
};

类A是类B的公用基类,类B是类C的保护基类。各成员在不同类中的访问属性如下:

根据以上分析,在派生类C的外面只能访问类C的成员函数f5,不能访问其他成员。 派生类C的成员函数f5能访问基类A的成员i、f2、j和派生类B的成员f3、f4。派生类B 的成员函数f3、f4能访问基类A的成员i、f2和j。

通过以上分析,可以看到:无论哪一种继承方式,在派生类中是不能访问基类的私有成员的,私有成员只能被本类的成员函数所访问,毕竟派生类与基类不是同一个类。

如果在多级派生时都采用公用继承方式,那么直到最后一级派生类都能访问基类的公用成员和保护成员。

如果采用私有继承方式,经过若干次派生之后,基类的所有的成员已经变成不可访问的了。

如果采用保护继承方式,在派生类外是无法访问派生类中的任何成员的。

而且经过多次派生后,人们很难清楚地记住哪些成员可以访问,哪些成员不能访问,很容易出错。因此,在实际中,常用的是公用继承。

(0)

相关推荐

  • C++聚合关系类的构造函数的调用顺序详解

    如图,表示一个聚合关系 下面就用简单的代码来实现 #pragma once class Engine { public: Engine(); ~Engine(); }; Engine.h #include <iostream> #include "Engine.h" using namespace std; Engine::Engine() { cout << "调用构造函数:Engine()" << endl; } Engine

  • 解析C++中多层派生时的构造函数及一些特殊形式

    C++多层派生时的构造函数 一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构.在上面叙述的基础上,不难写出在多级派生情况下派生类的构造函数. 通过例下面的程序,读者可以了解在多级派生情况下怎样定义派生类的构造函数.相信大家完全可以自己看懂这个程序. [例] 多级派生情况下派生类的构造函数. #include <iostream> #include<string> using namespace std; class Student//声明基类 { publi

  • 完全掌握C++编程中构造函数使用的超级学习教程

    构造函数是一种可初始化其类的实例的成员函数.构造函数具有与类相同的名称,没有返回值.构造函数可以具有任意数量的参数,类可以具有任意数量的重载构造函数.构造函数可以具有任何可访问性(公共.受保护或私有).如果未定义任何构造函数,则编译器会生成不采用任何参数的默认构造函数:可以通过将默认构造函数声明为已删除来重写此行为. 构造函数顺序 构造函数按此顺序执行工作: 按声明顺序调用基类和成员构造函数. 如果类派生自虚拟基类,则会将对象的虚拟基指针初始化. 如果类具有或继承了虚函数,则会将对象的虚函数指针

  • 详解C++中如何将构造函数或析构函数的访问权限定为private

    今天面试被问到了这个单例模式常用到的技术手段,下面进行分析:         很多情况下要求当前的程序中只有一个object.例如一个程序只有一个和数据库的连接,只有一个鼠标的object.通常我们都将构造函数的声明置于public区段,假如我们将其放入private区段中会发生什么样的后果?这意味着什么?         当我们在程序中声明一个对象时,编译器为调用构造函数(如果有的话),而这个调用将通常是外部的,也就是说它不属于class对象本身的调用,假如构造函数是私有的,由于在class外

  • 深入解析C++中派生类的构造函数

    基类的构造函数不能被继承,在声明派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数来完成.所以在设计派生类的构造函数时,不仅要考虑派生类新增的成员变量,还要考虑基类的成员变量,要让它们都被初始化. 解决这个问题的思路是:在执行派生类的构造函数时,调用基类的构造函数. 下面的例子展示了如何在派生类的构造函数中调用基类的构造函数. #include<iostream> using namespace std; //基类 class People{ protected: char *n

  • 浅谈C++中的构造函数分类及调用规则

    构造函数的分类 这里简单地将C++中的构造函数分一下类,直接看下面的代码表达,说明在注释中: #include <iostream> using namespace std; class Text { public: Text() // 无参数构造函数 { m_a = 0; m_b = 0; cout << "无参数构造函数" << endl; } Text(int a) // 有参数构造函数 { m_a = a; m_b = 0; cout <

  • 解析C++中构造函数的默认参数和构造函数的重载

    C++构造函数的默认参数 和普通函数一样,构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值. [例] #include <iostream> using namespace std; class Box { public : Box(int h=10,int w=10,int len=10); //在声明构造函数时指定默认参数 int volume( ); private : int height; int width; int l

  • 详解C++编程中多级派生时的构造函数和访问属性

    C++多层派生时的构造函数 一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构.在上面叙述的基础上,不难写出在多级派生情况下派生类的构造函数. 通过例下面的程序,读者可以了解在多级派生情况下怎样定义派生类的构造函数.相信大家完全可以自己看懂这个程序. [例] 多级派生情况下派生类的构造函数. #include <iostream> #include<string> using namespace std; class Student//声明基类 { publi

  • 详解Python编程中基本的数学计算使用

    数 在 Python 中,对数的规定比较简单,基本在小学数学水平即可理解. 那么,做为零基础学习这,也就从计算小学数学题目开始吧.因为从这里开始,数学的基础知识列位肯定过关了. >>> 3 3 >>> 3333333333333333333333333333333333333333 3333333333333333333333333333333333333333L >>> 3.222222 3.222222 上面显示的是在交互模式下,如果输入 3,就显

  • 详解C#编程中构造函数的使用

    当类或结构创建时,其构造函数调用.构造函数与选件类或结构相同,并且,它们通常用于初始化新对象的数据成员. 在下面的示例中,使用一个简单的构造函数定义了名为 Taxi 的类.然后使用 new 运算符来实例化该类.在为新对象分配内存之后,new 运算符立即调用 Taxi 构造函数. public class Taxi { public bool isInitialized; public Taxi() { isInitialized = true; } } class TestTaxi { stat

  • 详解C++编程中的私有继承和公有继承

    C++类的私有继承 在声明一个派生类时将基类的继承方式指定为private的,称为私有继承,用私有继承方式建立的派生类称为私有派生类(private derived class ), 其基类称为私有基类(private base class ). 私有基类的公用成员和保护成员在派生类中的访问属性相当于派生类中的私有成员,即派生类的成员函数能访问它们,而在派生类外不能访问它们.私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们.一个基类成员在基类中的访问属性和在派生类中

  • 详解Java编程中final,finalize,finally的区别

    final: final可以让你控制你的成员.方法或者是一个类是否可被覆写或继承等功能,这些特点使final在Java中拥有了一个不可或缺的地位,也是学习Java时必须要知道和掌握的关键字之一. final成员 当你在类中定义变量时,在其前面加上final关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变.其初始化可以在两个地方,一是其定义处,二是在构造函数中,两者只能选其一. 下面程序很简单的演示了final的常规用

  • 详解Swift编程中的常量和变量

    常量 常量指的是程序无法在其执行期间改变的固定值. 常量可以是任何像整型常量,浮点常量,字符常量或字符串的基本数据类型.也可以是枚举常量. 这些常量和常规变量处理一样,只是它们的值不能在定义后进行修改. 声明常量 使用常量时,则必须使用关键字 let 声明它们如下: 复制代码 代码如下: let constantName = <initial value> 下面是一个简单的例子来说明如何在 Swift 中声明一个常量: 复制代码 代码如下: import Cocoa let constA =

  • 详解C++编程中的虚函数

    我们知道,在同一类中是不能定义两个名字相同.参数个数和类型都相同的函数的,否则就是"重复定义".但是在类的继承层次结构中,在不同的层次中可以出现名字相同.参数个数和类型都相同而功能不同的函数. 人们提出这样的设想,能否用同一个调用形式,既能调用派生类又能调用基类的同名函数.在程序中不是通过不同的对象名去调用不同派生层次中的同名函数,而是通过指针调用它们.例如,用同一个语句"pt->display( );"可以调用不同派生层次中的display函数,只需在调用前

  • 详解C++编程中的文件流与字符串流

    C++文件流类与文件流对象 文件流是以外存文件为输入输出对象的数据流.输出文件流是从内存流向外存文件的数据,输入文件流是从外存文件流向内存的数据.每一个文件流都有一个内存缓冲区与之对应. 请区分文件流与文件的概念,不用误以为文件流是由若干个文件组成的流.文件流本身不是文件,而只是以文件为输入输出对象的流.若要对磁盘文件输入输出,就必须通过文件流来实现. 在C++的I/O类库中定义了几种文件类,专门用于对磁盘文件的输入输出操作. 除了标准输入输出流类istream.ostream和iostream

  • 详解C++编程中的析构函数

    C++析构函数 创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理工作(例如回收创建对象时消耗的各种资源),这个函数被称为析构函数. 析构函数(Destructor)也是一种特殊的成员函数,没有返回值,不需要用户调用,而是在销毁对象时自动执行.与构造函数不同的是,析构函数的名字是在类名前面加一个"~"符号. 注意:析构函数没有参数,不能被重载,因此一个类只能有一个析构函数.如果用户没有定义,那么编译器会自动生成. 析构函数举例: #inc

随机推荐