精华内容
下载资源
问答
  • 对于派生类的构造函数
    2021-01-21 21:17:50

    派生类构造函数

    • 默认情况

      • 基类的构造函数不被继承;

      • 派生类需要定义自己的构造函数。

    C++11规定

    using B::B;

    • 派生类新增成员可以通过类内初始值进行初始化。

    • 可用using语句继承基类构造函数。但是只能初始化从基类继承的成员。

    语法形式:

    建议
    如果派生类有自己新增的成员,且需要通过构造函数初始化,则派生类要自定义构造函数。

    若不继承基类的构造函数

    • 派生类新增成员:派生类定义构造函数初始化;

    • 继承来的成员:自动调用基类构造函数进行初始化;

    • 派生类的构造函数需要给基类的构造函数传递参数。

    单继承

    • 派生类只有一个直接基类的情况,是单继承。单继承时,派生类的构造函数只需要给一个直接基类构造函数传递参数。

    单继承时构造函数的定义语法

    派生类名::派生类名(基类所需的形参,本类成员所需的形参):
    基类名(参数表), 本类成员初始化列表
    {
    //其他初始化;
    };

    单继承时的构造函数举例

    #include<iostream>
    using namespace std;
    class B {
    public:
        B();
        B(int i);
        ~B();
        void print() const;
    private:
        int b;
    };
    
    B::B() {
        b=0;
        cout << "B's default constructor called." << endl;
    }
    B::B(int i) {
        b=i;
        cout << "B's constructor called." << endl;
    }
    B::~B() {
        cout << "B's destructor called." << endl;
    }
    void B::print() const {
        cout << b << endl;
    }
    
    class C: public B {
    public:
        C();
        C(int i, int j);
        ~C();
        void print() const;
    private:
        int c;
    };
    C::C() {
        c = 0;
        cout << "C's default constructor called." << endl;
    }
    C::C(int i,int j): B(i), c(j){
        cout << "C's constructor called." << endl;
    }
    
    C::~C() {
        cout << "C's destructor called." << endl;
    }
    void C::print() const {
        B::print();
        cout << c << endl;
    }
    
    int main() {
        C obj(5, 6);
        obj.print();
        return 0;
    }
    

    多继承

    • 多继承时,有多个直接基类,如果不继承基类的构造函数,派生类构造函数需要给所有基类构造函数传递参数。我们来看一下语法规定

    多继承时构造函数的定义语法

    派生类名::派生类名(参数表) :
    基类名1(基类1初始化参数表),
    基类名2(基类2初始化参数表),

    基类名n(基类n初始化参数表),
    本类成员初始化列表
    {
    //其他初始化;
    };

    派生类与基类的构造函数

    • 当基类有默认构造函数时

      • 派生类构造函数可以不向基类构造函数传递参数。

      • 构造派生类的对象时,基类的默认构造函数将被调用。

    • 如需执行基类中带参数的构造函数

      • 派生类构造函数应为基类构造函数提供参数。

    多继承且有对象成员时派生的构造函数定义语法

    派生类名::派生类名(形参表):
    基类名1(参数), 基类名2(参数), …, 基类名n(参数),
    本类成员(含对象成员)初始化列表
    {
    //其他初始化
    };

    构造函数的执行顺序

    • 调用基类构造函数。

      • 顺序按照它们被继承时声明的顺序(从左向右)。
    • 对初始化列表中的成员进行初始化。

      • 顺序按照它们在类中定义的顺序。

      • 对象成员初始化时自动调用其所属类的构造函数。由初始化列表提供参数。

    • 执行派生类的构造函数体中的内容。

    派生类构造函数举例

    #include <iostream>
    using namespace std;
    class Base1 {//基类Base1,构造函数有参数
    public:
        Base1(int i) 
      { cout << "Constructing Base1 " << i << endl; }
    };
    class Base2 {//基类Base2,构造函数有参数
    public:
        Base2(int j) 
      { cout << "Constructing Base2 " << j << endl; }
    };
    class Base3 {//基类Base3,构造函数无参数
    public:
        Base3() 
      { cout << "Constructing Base3 *" << endl; }
    };
    
    class Derived: public Base2, public Base1, public Base3 {
    public: 
        Derived(int a, int b, int c, int d): Base1(a), member2(d), member1(c), Base2(b)
      //此处的次序与构造函数的执行次序无关
        { }
    private:
        Base1 member1;
        Base2 member2;
        Base3 member3;
    };
    
    int main() {
        Derived obj(1, 2, 3, 4);
        return 0;
    }
    
    更多相关内容
  • 派生类的数据成员由所有基类的数据成员与派生类新增的数据成员共同组成,如果派生类新增成员中包括其他类的对象(子对象),派生类的数据成员中实际上还间接包括了这些对象的数据成员。
  • 基类的构造函数不能被继承,在声明派生类时,对继承过来的成员变量的初始化工作也要由派生类构造函数来完成。所以在设计派生类构造函数时,不仅要考虑派生类新增的成员变量,还要考虑基类的成员变量,要让它们都...
  • 在上面叙述的基础上,不难写出在多级派生情况下派生类构造函数。 通过例下面的程序,读者可以了解在多级派生情况下怎样定义派生类构造函数。相信大家完全可以自己看懂这个程序。 [例] 多级派生情况下派生类的...
  • 《Visual C++2012入门经典(第6版)》实例,在派生类构造函数中调用基类的构造函数
  • 但有一点与私有成员不同,保护成员可以被派生类的成员函数引用。 如果基类声明了私有成员,那么任何派生类都是不能访问它们的,若希望在派生类中能访问它们,应当把它们声明为保护成员。如果在一个类中声明了保护...

    派生类的构造函数和析构函数

    • 构造函数的主要作用是对数据成员初始化。基类的构造函数是不能继承的,在声明派生类时,派生类并没有把基类的构造函数继承过来,因此,对继承过来的基类成员初始化的工作也要由派生类的构造函数承担。所以在设计派生类的构造函数时,不仅要考虑派生类所增加的数据成员的初始化,还应当考虑基类的数据成员初始化。也就是说,希望在执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。解决这个问题的思路是:在执行派生类的构造函数时,调用基类的构造函数。

    派生类构造函数一般形式为:

    派生类构造函数名(总参数表):基类构造函数名(参数表)
    	{派生类中新增数据成员初始化语句}
    

    简单的派生类的构造函数

    例:定义简单的派生类的构造函数

    #include <iostream>
    #include<string>
    using namespace std;
    class Student//声明基类Student
    {
    public:
    	Student(int n, string nam, char s) //定义基类构造函数
    	{
    		num = n;
    		name = nam;
    		sex = s;
    	}
    	~Student() {} //基类析构函数
    protected: //保护部分
    	int num;
    	string name;
    	char sex;
    };
    
    class Student1 : public Student //声明派生类Student1
    {
    public: //派生类的公用部分
    	Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s) //派生类构造函数
    	{
    		age = a; //在函数体中只对派生类新增的数据成员初始化
    		addr = ad;
    	}
    	void show()
    	{
    		cout << "num: " << num << endl;
    		cout << "name: " << name << endl;
    		cout << "sex: " << sex << endl;
    		cout << "age: " << age << endl;
    		cout << "address: " << addr << endl << endl;
    	}
    	~Student1() {} //派生类析构函数
    private: //派生类的私有部分
    	int age;
    	string addr;
    };
    
    int main() 
    {
    	Student1 stud1(10010, "Wang-li ", ' f', 19, "115 Beijing Road,Shanghai"); 
    	Student1 stud2(10011, "Zhang-fun ", ' m', 21, "213 Shanghai Road,Beijing"); 
    	stud1.show(); //输出第一个学生的数据
    	stud2.show(); //输出第二个学生的数据
    	return 0;
    }
    

    程序分析:

    • 从上面列出的派生类Student1构造函数首行中可以看到,派生类构造函数名(Student1)后面括号内的参数表中包含参数的类型和参数名(如:int n),而基类构造函数名后面括号内的参数表列只有参数名而不包括参数类型(如:n,nam,s),因为在这里不是定义基类构造函数,而是调用基类构造函数,因此这些参数是实参而不是形参。它们可以是常量、全局变量和派生类构造函数总参数表中的参数。
    • 在上例中也可以将派生类构造函数在类外面定义,而在类体中只写该函数的声明:Student1(int n, string nam, char s, int a, string ad);

    在类的外面定义派生类构造函数:

    Student1::Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)
    {
    	age = a; //在函数体中只对派生类新增的数据成员初始化
    	addr = ad;
    }
    
    • 注意:在类中对派生类构造函数作声明时,不包括上面给出的一般形式的"基类构造函数名(参数表)"部分,即Student(n,nam,s)。只在定义函数时才将它列出。
    • 不仅可以利用初始化表对构造函数的数据成员初始化,而且可以利用初始化表调用派生类的基类构造函数,实现对基类数据成员的初始化。也可以在同一个构造函数的定义中同时实现这两种功能。例如:将派生类的基类构造函数的定义采用了下面的形式:
    Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s) //派生类构造函数
    {
    	age = a; //在函数体中只对派生类新增的数据成员初始化
    	addr = ad;
    }
    

    可以将对age和addr的初始化也用初始化表处理,将构造函数改写为以下形式:Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s), age(a), addr(ad) {}

    • 在建立一个对象时,执行构造函数的顺序是:①派生类构造函数先调用基类构造函数;②再执行派生类构造函数本身(即派生类构造函数的函数体)。
    • 在派生类对象释放时,先执行派生类析构函数~Student1(),再执行其基类析构函数~Student。

    运行结果:

    有子对象的派生类的构造函数

    • 类的数据成员中还可以包含类对象,如可以在声明一个类时包含这样的数据成员:Student s1; //Student是已声明的类名,s1是Student类的对象
      这时,s1就是类对象中的内嵌对象,称为子对象(subobject),即对象中的对象

    例:包含子对象的派生类的构造函数

    #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 << "name:" << name << endl;
    	}
    protected: //保护部分
    	int num;
    	string name;
    };
    
    class Student1 : public Student //声明公用派生类Student1
    {
    public:
    	Student1(int n, string nam, int n1, string nam1, int a, string ad) : Student(n, nam), monitor(n1, nam1)//派生类构造函数
    	{
    		age = a;
    		addr = ad;
    	}
    	void show() {
    		cout << "This student is:" << endl;
    		display(); //输出num和name
    		cout << "age:" << age << endl; //输出age
    		cout << "address:" << addr << endl << endl; //输出addr
    	}
    	void show_monitor() //成员函数,输出子对象
    	{
    		cout << "Class monitor is:" << endl;
    		monitor.display(); //调用基类成员函数
    	}
    private: //派生类的私有数据
    	Student monitor; //定义子对象(班长)
    	int age;
    	string addr;
    };
    
    int main()
    {
    	Student1 stud1(10010, " Wang_li", 10001, "Li_sun", 19, "115 BeijingRoad, Shanghai");
    	stud1.show(); //输出学生的数据
    	stud1.show_monitor(); //输出子对象的数据
    	return 0;
    }
    

    程序分析:

    • 派生类Student1中有一个数据成员:Student monitor; //定义子对象monitor(班长),"班长"的类型不是简单类型,它是Student类的对象。应当在建立对象时对它的数据成员初始化,显然不能在声明派生类时对它初始化(如:Student monitor(10001,"Li_sun");),因为类是抽象类型,只是一个模型,是不能有具体的数据的,而且每一个派生类对象的子对象一般是不相同的。因此子对象的初始化是在建立派生类时通过调用派生类构造函数来实现的。
    • 程序中派生类构造函数首部是:Student1(int n, string nam, int n1, string nam1, int a, string ad) : Student(n, nam), monitor(n1, nam1)

    运行结果:

    • 派生类构造函数的任务应该包括3个部分:
    1. 对基类数据成员初始化
    2. 对子对象数据成员初始化
    3. 对派生类数据成员初始化
    • 定义派生类构造函数的一般形式为:
    派生类构造函数名(总参数表):基类构造函数名(参数表),子对象名(参数表)
    	{派生类中新增数据成员初始化语句}
    
    • 执行派生类构造函数的顺序是:
    1. 调用基类构造函数,对基类数据成员初始化
    2. 调用子对象构造函数,对子对象数据成员初始化
    3. 再执行派生类构造函数本身,对派生类数据成员初始化
    • 派生类构造函数的总参数表列中的参数,应当包括基类构造函数和子对象的参数表列中的参数。基类构造函数和子对象的次序可以是任意的,如上面的派生类构造函数首部可以写成Student1(int n, string nam, int n1, string nam1, int a, string ad) :monitor(n1, nam1), Student(n, nam)。编译系统是根据相同的参数名(而不是根据参数的顺序)来确立它们的传递关系的。

    多层派生时的构造函数

    • 一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构。

    例:多级派生情况下派生类的构造函数

    #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, string nam, int a) :Student(n, nam) //派生类构造函数
    	{
    		age = a; //在此处只对派生类新增的数据成员初始化
    	}
    	void show() //输出num,name和age
    	{
    		display(); //输出num和name
    		cout << "age:" << age << endl; //输出age
    	}
    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和age
    		cout << "score:" << score << endl; //输出score
    	}
    private:
    	int score; //增加一个数据成员
    };
    
    int main()
    {
    	Student2 stud(10010, "Li", 17, 89);
    	stud.show_all(); //输出学生的全部数据
    	return 0;
    }
    

    程序分析:

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

    • 基类的构造函数首部:Student(int n, string nam)
    • 派生类Student1的构造函数首部:Student1(int n, string nam, int a) :Student(n, nam)
    • 派生类Student1的构造函数首部:Student2(int n,string nam,int a,int s):Student1(n,nam,a)
      注意:不要写成Student2(int n,string nam,int a,int s):Student(n, nam),Student1(n,nam,a)。不要列出每一层派生类的构造函数,只须写出其上一层派生类(即它的直接基类)的构造函数即可。

    运行结果:

    • 在声明Student2类对象时,调用Student2构造函数;在执行Student2构造函数时,先调用Student1构造函数;在执行Student1构造函数时,先调用基类Student构造函数。

    派生类构造函数的特殊形式

    在使用派生类构造函数时,可以有以下两种特殊的形式:

    1. 当不需要对派生类新增的成员进行任何初始操作时,派生类构造函数的函数体可以为空,即构造函数是空函数
      如:Student1(int n,string nam,int n1,string nam1):Student(n,nam),monitor(n1,nam1){ }
      此时,派生类构造函数的参数个数等于基类构造函数和子对象的参数个数之和,派生类构造函数的全部参数都传递给基类构造函数和子对象,在调用派生类构造函数时不对派生类的数据成员初始化。此派生类构造函数的作用只是为了将参数传递给基类构造函数和子对象,并在执行派生类构造函数时调用基类构造函数和子对象构造函数。在实际工作中常见这种用法。
    2. 如果在基类中没有定义构造函数,或定义了没有参数的构造函数,那么,在定义派生类构造函数时可以不写基类构造函数。因为此时派生类构造函数没有向基类构造函数传递参数的任务。在调用派生类构造函数时,系统会自动首先调用基类的默认构造函数。
    • 如果在基类和子对象类型的声明中都没有定义带参数的构造函数,而且也不需对派生类自己的数据成员初始化,则可以不必显式地定义派生类构造函数。因为此时派生类构造函数既没有向基类构造函数和子对象构造函数传递参数的任务,也没有对派生类数据成员初始化的任务。在建立派生类对象时系统会自动调用系统提供的派生类的默认构造函数,并在执行派生类默认构造函数的过程中,调用基类的默认构造函数和子对象类型默认构造函数。
    • 如果在基类或子对象类型的声明中定义了带参数的构造函数,那么就必须显式地定义派生类构造函数,并在派生类构造函数中写出基类或子对象类型的构造函数及其参数表。
    • 如果在基类中既定义无参的构造函数,又定义了有参的构造函数(构造函数重载),则在定义派生类构造函数时既可以包含基类构造函数及其参数,也可以不包含基类构造函数。在调用派生类构造函数时,根据构造函数的内容决定调用基类的有参的构造函数还是无参的构造函数。

    派生类的析构函数

    • 析构函数的作用是在对象撤销之前,进行必要的清理工作。当对象被删除时,系统会自动调用析构函数。析构函数比构造函数简单,没有类型也没有参数。
    • 在派生时,派生类是不能继承基类的析构函数的,也需要通过派生类的析构函数去调用基类的析构函数。在派生类中可以根据需要定义自己的析构函数,用来对派生类中所增加的成员进行清理工作。基类的清理工作仍然由基类的析构函数负责。在执行派生类的析构函数时,系统会自动调用基类的析构函数和子对象的析构函数对基类和子对象进行清理。
    • 调用的顺序与构造函数正好相反:先执行派生类自己的析构函数,对派生类新增加的成员进行清理,然后调用子对象的析构函数对子对象进行清理最后调用基类的析构函数,对基类进行清理。

    多重继承

    • 单继承:一个类是从一个基类派生而来的
    • 多重继承:一个派生类有两个或多个基类,派生类从两个或多个基类中继承所需的属性

    声明多重继承的方法

    • 如果已声明了类A、类B和类C,可以声明多重继承的派生类D:
    class D:public A,private B,protected C
    	{类D新增加的成员}
    

    D是多重继承的派生类,它以公用继承方式继承A类,以私有继承方式继承B类,以保护继承方式继承C类。D按不同的继承方式的规则继承A、B、C的属性,确定各基类的成员在派生类中的访问权限。

    多重继承派生类的构造函数

    • 多重继承派生类的构造函数形式与单继承时的构造函数形式基本相同,只是在初始表中包含多个基类构造函数。如:
    派生类构造函数名(总参数表列):基类1构造函数(参数表列),基类2构造函数(参数表列),基类3构造函数(参数表列)
    {
        派生类中新增数成员据成员初始化语句
    }
    

    各基类的排列顺序任意。派生类构造函数的执行顺序同样为先调用基类的构造函数,再执行派生类构造函数的函数体。调用基类构造函数的顺序是按照声明派生类时基类出现的顺序。

    例:声明一个教师(Teacher)类和一个学生(Student)类,用多重继承的方式声明一个在职研究生(Graduate)派生类(在职教师攻读研究生)。

    #include <iostream>
    #include <string>
    using namespace std;
    class Teacher //声明类Teacher(教师)类
    {
    public: //公用部分
    	Teacher(string nam, int a, string t) //构造函数
    	{
    		name = nam;
    		age = a;
    		title = t;
    	}
    	void display()
    	{
    		cout << "name:" << name << endl;
    		cout << "age:" << age << endl;
    		cout << "title:" << title << endl;
    	}
    protected: //保护部分
    	string name;
    	int age;
    	string title; //职称
    };
    
    class Student //定义类Student(学生)
    {
    public:
    	Student(string nam, char s, float sco) //构造函数
    	{
    		name1 = nam;
    		sex = s;
    		score = sco;
    	}
    	void display1()
    	{
    		cout << "name:" << name1 << endl;
    		cout << "sex:" << sex << endl;
    		cout << "score:" << score << endl;
    	}
    protected: //保护部分
    	string name1;
    	char sex;
    	float score; //成绩
    };
    
    class Graduate :public Teacher, public Student
    {
    public:
    	Graduate(string nam,int a,char s,string t,float sco,float w):Teacher(nam,a,t),Student(nam,s,sco),wage(w){}
    	void show() //输出研究生的有关数据
    	{
    		cout << "name:" << name1 << endl;
    		cout << "age:" << age << endl;
    		cout << "sex:" << sex << endl;
    		cout << "score:" << score << endl;
    		cout << "title:" << title << endl;
    		cout << "wages:" << wage << endl;
    	}
    private:
    	float wage; //津贴
    };
    
    int main()
    {
    	Graduate grad1("Wang_li", 24, 'f', "assistance", 89.5, 1200);
    	grad1.show();
    	return 0;
    }
    

    程序分析:

    • 由于在两个基类中把数据成员声明为protected,因此可以通过派生类的成员函数引用基类的成员。如果在基类中把数据成员声明为private,则派生类成员函数不能引用这些数据。
    • 在两个基类中分别用name和name1来代表姓名,其实这是同一个人的名字,从Graduate类的构造函数中可以看到总参数表中的参数nam分别传递给两个基类的构造函数,作为基类构造函数的实参。现在两个基类都需要有姓名这一项,能否用同一个名字name来代表?——在本程序中只作这样的修改是不行的,因为在同一个派生类中存在着两个同名的数据成员,在派生类的成员函数show中引用name时就会出现二义性,编译系统无法判定应该选择哪一个基类中的name。解决这个问题有一个好方法:在两个基类中可以都使用同一个数据成员名name,而在show函数中引用数据成员时指明其作用域,如:cout<<"name:”<<Teacher : : name<<endl;,这就是唯一的,不致引起二义性,能通过编译,正常运行。

    运行结果:

    多重继承引起的二义性问题

    • 多重继承能够有效地处理一些较复杂的问题,使编写程序具有灵活性,但是多重继承也增加了程序的复杂度,使程序的编写和维护变得相对困难,容易出错。其中最常见的问题就是继承的成员同名而产生的二义性(ambiguous)问题。

    类A和类B中都有成员函数display和数据成员a,类C是类A和类B的直接派生类。分别讨论下列3种情况:

    1. 两个基类有同名成员(如图1所示)
    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();
    };
    

    程序分析:

    • 如果在main函数中定义C类对象c1,并调用数据成员a和成员函数display:
    C c1; //定义C类对象c1
    c1.a = 3; //引用c1的数据成员a
    c1.display(); //调用c1的成员函数display
    
    • 由于基类A和基类B都有数据成员a和成员函数display,编译系统无法判定要访问的是哪一个基类的成员,因此,程序编译出错。解决此问题,可以用基类名来限定:
    c1.A::a = 3; //引用c1对象中的基类A的数据成员a
    c1.A::display(); //调用c1对象中的基类A的成员函数display
    
    • 如果派生类C中的成员函数show访问基类A的display和a,可以不必写对象名而直接写
    A::a = 3; //指当前对象
    A::display();
    
    • 为清楚起见,图1应改为图2或图3形式表示
    1. 两个基类和派生类三者都有同名成员(如图4)
    class A
    {
    public:
    	int a;
    	void display();
    };
    
    class B
    {
    public:
    	int a;
    	void display();
    };
    
    class C :public A, public B //公用继承
    {
    	int a;
    	void display();
    };
    

    程序分析:

    • 如果在main函数中定义C类对象c1,并调用数据成员a和成员函数display:
    C c1;
    c1.a = 3;
    c1.display();
    
    • 执行时访问的是派生类C中的成员。
      规则是:基类的同名成员在派生类中被屏蔽,成为"不可见"的,或者说,派生类新增加的同名成员覆盖了基类中的同名成员。因此如果在定义派生类对象的模块中通过对象名访问同名的成员,则访问的是派生类的成员。请注意:不同的成员函数,只有在函数名和参数个数相同、类型相匹配的情况下才发生同名覆盖,如果只有函数名相同而参数不同,不会发生同名覆盖,而属于函数重载
    • 即有3个a,3个display函数
    • 同样,要在派生类外访问基类A中的成员,应指明作用域A,写成以下形式:
    c1.A::a = 3; //表示派生类对象c1中的基类A中的数据成员a
    c1.A::display(); //表示派生类对象c1中的基类A中的成员函数display
    

    3.如果类A和类B是从同一个基类派生的(如图5)

    class N
    {
    public:
    	int a;
    	void display() { cout << "A::a=" << a << endl; }
    };
    
    class A :public N
    {
    public:
    	int a1;
    };
    
    class B :public N
    {
    public:
    	int a2;
    };
    
    class  C :public A, public B
    {
    public:
    	int a3;
    	void show() { cout << "a3=" << a3 << endl; }
    };
    
    int main()
    {
    	C c1; //定义C类对象c1
    	...
    }
    

    程序分析:

    • 在类A和类B中虽然没有定义数据成员a和成员函数display,但是它们分别从类N继承了数据成员a和成员函数display,这样在类A和类B中同时存在着两个同名的数据成员a和成员函数display。它们是类N成员的拷贝。类A和类B中的数据成员a代表两个不同的存储单元,可以分别存放不同的数据。在程序中可以通过类A和类B的构造函数去调用基类N的构造函数,分别对类A和类B的数据成员a初始化。
    • 访问类A中基类N继承下来的成员,显然不能用c1.a = 3; c1.display();c1.N::a = 3; c1.N::display();。因为这样依然无法区别是类A中从基类N继承下来的成员,还是类B中从基类N继承下来的成员。应当通过类N的直接派生类名来指出要访问的是类N的哪一个派生类中的基类成员。如c1.A::a = 3; c1.A::display(); //要访问的是类N的派生类A中的基类成员

      派生类C中成员的情况:
    展开全文
  • 派生类构造函数(c++)

    千次阅读 2022-04-12 16:00:45
    class Bug { private : int nLegs; int nColor;...class FlyBug: public Bug // FlyBug是Bug的派生类 { int nWings; public: FlyBug( int legs,int color, int wings);//为什么给3个 }; .
    class Bug  {
    	private :
    		int nLegs;     int nColor;
    	public:
    		int nType;
    		Bug (  int legs, int color);
    		void PrintBug (){ };
    };
    class FlyBug: public Bug // FlyBug是Bug的派生类
    {
    		int nWings;
    	public:
    		FlyBug( int legs,int color, int wings);//为什么给3个
    };
    

    问题解释:给基类和自己的成员初始化

    Bug::Bug( int legs, int color)
    {
    	nLegs = legs;
    	nColor = color;
    }
    //错误的FlyBug构造函数
    FlyBug::FlyBug ( int legs,int color, int wings)
    {
    	nLegs = legs;     // 不能访问
    	nColor = color;  // 不能访问
                nType = 1; // ok
    	nWings = wings;
    }
    //正确的FlyBug构造函数:
    FlyBug::FlyBug ( int legs, int color, int wings):Bug( legs, color)
    {
    	nWings = wings;
    }
    int main() {
    FlyBug fb ( 2,3,4);
    fb.PrintBug();
    fb.nType = 1; 
    fb.nLegs = 2 ;  // error.  nLegs is private
    return 0;
    }
    

    在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象中从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。如下:

    FlyBug::FlyBug ( int legs, int color, int wings):Bug( legs, color)

     

     

    展开全文
  • 派生类构造函数和析构函数的执行顺序
  • 派生类构造函数

    2019-05-26 10:39:58
    派生类构造函数的定义与声明 派生类构造函数的功能 2.继承与派生     继承与派生其实是指两种关系! 这两种关系就像家庭族谱里边的长辈与晚辈的某种联系,我们可以这样理解:你和你的父亲肯定在性格或者为人...

    前言:
      前文我们谈到过构造函数《C++的构造函数》,现在我们主要讨论构造函数在派生类里的运用。

    1.必备知识/概念

    1. 继承与派生
    2. 派生类构造函数的定义与声明
    3. 派生类构造函数的功能

    2.继承与派生

        继承派生其实是指两种关系!
    这两种关系就像家庭族谱里边的长辈与晚辈的某种联系,我们可以这样理解:你和你的父亲肯定在性格或者为人处世等方面有诸多相似之处,我们说那是你遗传了你父亲的某些特质。也就是说你继承了你父亲的这些特点,而反过来,我们说是你父亲把这些特质派生给了你。

    在这里插入图片描述
    我们现在把这个关系重新命名,父亲=基类;儿子=派生类。它们之间的箭头是由派生指向基类
    总结成一句话:
          父亲派生给儿子,儿子继承父亲。

    3.派生类构造函数的定义与声明

       我们首先定义一个基类Student,在定义一个派生类Student1,通过派生类去访问基类Student的成员数据,主函数调用派生类的成员函数show进行输出。
       以上是我们要写的一个业务逻辑,我们在主函数建立对象的时候直接给出参数,进行输出。

       1.首先定义基类Student,也就是我们说的父亲。

    class Student
    {
    public:
    	Student(int n, string nam, char s) :num(n), name(nam), sex(s) {};//定义基类构造函数
    
    	~Student()//定义基类的析构函数
    	{
    
    	}
    protected:
    	int num;
    	string name;
    	char sex;
    };
    

    基类的构造函数进行数据初始化,我们用的是初始化表,这是我个人比较喜欢用的,因为比较方便。

    Student(int n, string nam, char s) :num(n), name(nam), sex(s) {};
    

    2.定义一个派生类Student1,去访问基类的数据成员

    class Student1:public Student
    {
    public:
    	Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s), age(a), addr(ad) {}//定义派生类构造函数
    	void show()
    	{
    		cout << "num:" << num << endl;
    		cout << "name:"<<name << endl;
    		cout << "sex:" << sex << endl;
    		cout << "age:" << age << endl;
    		cout << "addr:" << addr << endl;
    	}
    	~Student1() {}//派生类析构函数
    private:
    	int age;
    	string addr;
    };
    

    在派生类里我们需要知道下面几点:

    1. 继承方式的定义,这里我们定义的公用继承。
    2. 派生类的公用成员函数show能够访问基类的保护protected数据成员
    3. 派生类的作用就是为基类补充数据成员ageaddr

    4.主函数的写法

    int main()
    {
    	Student1 stud1{ 100010,"wang",'f',19,"115 Beijing Road,Shanghai" };
    	Student1 stud2{ 100011,"Zhang",'m',21,"213 Shanghai Road,Beijing" };
    	stud1.show();
    	stud2.show();
    	return 0;
    }
    

    建立对象stud1stud2,带着参数进行调用函数show

    5.派生类构造函数的功能

    数据初始化!

    展开全文
  • C++派生类构造函数的写法

    千次阅读 2020-04-06 09:46:42
    定义基类shape,它有默认的构造函数和析构函数; 把点point类声明为shape的派生类,它包含两个数据成员x和y和输出函数display(); 把圆circle定义为点point类的派生类,它在点point的基础上增加一个数据成员radius...
  • 派生类构造函数可以自动调用基类的默认构造函数,但是前提是默认构造函数必须存在。通常情况下,默认构造函数系统会自动生成的,但是如果在基类中,我们自己定义了一个带参数的构造函数,这个时候,系统是不会为基类...
  • 多重继承派生类构造函数

    千次阅读 2019-06-03 16:54:28
    #include<iostream> #include<string> using namespace std; class Teacher { public: Teacher(string nam, int a, string t) { name = nam; age = a; title = t; ... cou...
  • 派生类构造函数执行顺序

    千次阅读 2020-11-06 21:54:00
    派生类构造函数可以不向基类构造函数传递参数。 构造派生类的对象时,基类的默认构造函数将被调用。 2.如需执行基类中带参数的构造函数 派生类构造函数应为基类构造函数提供参数。 构造函数的执行顺序 1,调用基类...
  • C++继承派生类构造函数的写法

    千次阅读 2019-06-16 22:51:01
    C++有三大思想:抽象与封装、继承与派生、多态性,是c++开发人员面对对象编程必须掌握的知识。 初学者对子类继承中构造函数的写法有时会存在一些问题。即子类继承基类时,子类的...②再执行派生类构造函数本身(...
  • 6-5 多重继承派生类构造函数

    千次阅读 2020-05-15 17:16:55
    //编者注:考题版权归属版权方,作答代码...根据所给的基类Student和Teacher,定义Graduate 定义: #include <iostream> #include <string> using namespace std; class Teacher {public: Teach
  • 主要介绍了C#中派生类调用基类构造函数用法,实例分析了派生类调用基类构造函数的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
  • C++派生类构造函数

    千次阅读 多人点赞 2018-07-17 14:15:53
    构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类构造函数,当然更不能成为普通的成员函数。 在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的...
  • #C++ 1:派生类构造函数的类外定义 最近上课在看课本的时候发现派生类都是在类内定义的,自己写代码想要按普通类的方式类外定义的时候出现了报错,如下: //CPerson的派生类:CStudent class CStudent:public ...
  • #include<iostream> using namespace std; class Base//声明基类base { public: Base(int sa) ...class Base1:virtual public Base//声明base是base1的虚基类 { public: Base1(int
  • 创建派生类对象时,构造函数的执行顺序是:基类构造函数派生类对象成员构造函数派生类本身的构造函数。对象创建时,代码的加载顺序是:静态代码、非静态代码、构造方法。创建派生类对象时,构造函数的执行顺序是...
  • (1)基类的构造函数和析构函数不能被继承,在派生类中,如果对派生类新增成员进行初始化,就必须加入派生类构造函数 (2)从基类继承的成员仍有基类的构造函数完成 (3)但需要在派生类构造函数中对基类的构造...
  • C++派生类构造函数构造函数的执行顺序)

    万次阅读 多人点赞 2018-06-16 16:01:55
    1、单继承时,派生类构造函数总是先调用基类构造函数再执行其他代码 1.1 派生类调用基类的构造函数  类的构造函数不能被继承,构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,...
  • C++初始化派生类构造函数
  •  派生类构造函数名(总参数表):基类构造函数名(参数表) {派生类中新增数据成员初始化语句} 2 有子对象的派生类的构造函数的一般形式为:  派生类构造函数名(总参数表):基类构造函数名(参数表),子...
  • 根据所给的基类Student和Teacher,定义Graduate 定义: #include <iostream> #include <string> using namespace std; class Teacher {public: Teacher(string nam,int a,string t) {name=nam...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 162,597
精华内容 65,038
热门标签
关键字:

对于派生类的构造函数