1.类的继承与派生
类的定义:
class 派生类名:继承方式 基类名1,继承方式 基类名2,...,继承方式 基类名n
{
派生类成员声
};
派生类的过程:
吸收基类成员 改造基类成员 添加新成员
2.访问控制(公有,保护,私有继承)
public修饰的类成员可以在类外被访问,而protected与private则不可以
3.类型兼容原则:
类型兼容规则是指在需要基类对象的任何地方,都可以使用公用派生类的对象来替代。
替代包括以下情况:
派生类的对象可以隐含转换为基类对象
派生类的对象可以初始化基类引用
派生类的指针可以隐含转换为基类的指针
在替代之后,派生类对象就可以作为基类的对象使用,但只能使用基类继承的成员。
4派生类的构造和析构函数:构造函数,复制构造函数,析构函数
class Base1
{
public:
Base1(int i) { cout << "constructing Base1" << " "<<i<< endl; }
~Base1() { cout << "destructing Base1" << endl; }
};
class Base2
{
public:
Base2(int j) { cout << "constructing Base2" << " "<<j << endl; }
~Base2() { cout << "destructing Base2" << endl; }
};
class Base3
{
public:
Base3() { cout << "constructing Base3*" << endl; }
~Base3() { cout << "destructing Base3" << endl; }
};
//派生新类Derived,注意基类名顺序
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;
}
继承关系中构造函数调用顺序:
1.基类的构造函数(按照继承列表中的顺序调用)
2.派生类中对象的构造函数(按照派生类中成员对象声明顺序调用
)
3.派生类构造函数体
继承关系中析构函数调用顺序:
1.派生类析构函数
2.派生类包含成员对象的析构函数
3.基类的析构函数
注意:1. 基类的 private 成员在派生类中是不能被访问的,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为 protected 。可以看出保护成员限定符是因继承才出现的。
2. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
3. 在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承
5.派生类成员的标识与访问(作用域分辨符,虚基类,虚基类及其派生类的构造函数)
作用域分辨符:1.类名::成员名//数据成员 2.类名::成员名(参数表)//函数成员
class Base1
{
public:
int var;
void fun() { cout << "member of base1" << endl; }
};
class Base2
{
public:
int var;
void fun() { cout << "member of base2" << endl; }
};
class Derived :public Base1, public Base2
{
public:
int var;
void fun() { cout << "member of Derived" << endl; }
};
int main()
{
Derived d;
Derived*p = &d;
d.var = 1;
d.fun();
d.Base1::var = 2;
d.Base1::fun();
p->Base2::var = 3;
p->Base2::fun();
}
如果class Derived :public Base1, public Base2 {};在主函数中
d.var = 1;d.fun();这两句是错的,会产生二义性。
如果不希望产生二义性,则
class Derived :public Base1, public Base2
{
public:
using Base1::var;
using Base1::fun() ;
};
如果某个派生类的部分或全部直接基类是从另一个共同的基类派生而来的,在这些基类中,从上一级基类继承来的成员就具有相同的名称,
因此派生类中就会产生同名现象,对这种类型的同名成员也要使用作用于分辨符来唯一标识,而且必须用直接基类进行限定
class Base0 { public: int var0; void fun0() { cout << "member of base0" << endl; } }; class Base1:public Base0 { public: int var0; }; class Base2:public Base0 { public: int var2; }; class Derived :public Base1, public Base2 { public: int var; void fun() { cout << "member of Derived" << endl; } }; int main() { Derived d; d.Base1::var0 = 2; d.Base1::fun0(); d.Base2::var0 = 2; d.Base2::fun0(); return 0; }
也可设为虚基类
语法形式:class 派生类名:virtual 继承方式 基类名
class Base0
{
public:
int var0;
void fun0() { cout << "member of base0" << endl; }
};
class Base1 :virtual public Base0
{
public:
int var0;
};
class Base2 :virtual public Base0
{
public:
int var2;
};
class Derived :public Base1, public Base2
{
public:
int var;
void fun() { cout << "member of Derived" << endl; }
};
int main()
{
Derived d;
d.var0 = 2;//直接访问虚基类数据成员
d.fun0();//直接访问虚基类数据成员
return 0;
}
虚基类及其派生类的构造函数
class Base0
{
public:
Base0(int var) :var0(var) {}
int var0;
void fun0() { cout << "member of Base0" << endl; }
};
class Base1 :virtual public Base0
{
public:
Base1(int var) :Base0(var) {}
int var1;
};
class Base2 :virtual public Base0
{
public:
Base2(int var) :Base0(var) {}
int var2;
};
class Derived :public Base1, public Base2
{
public:
Derived(int var) :Base0(var), Base1(var), Base2(var) {}
int var;
void fun() { cout << "member of Derived" << endl; }
};
int main()
{
Derived d(1);//建立一个对象时,只有最远派生类的构造函数通过调用虚基类的函数进行初始化
d.var = 2;
d.fun();
return 0;
}
构建一个类的对象的一般顺序
1.如果该类有直接或者间接的虚基类,则先执行虚基类的构造函数。
2.如果该类有其他基类,则按照它们在继承声明的列表中出现的次序,分别执行它们的构造函数,但构造过程中,不在执行它们基类的构造函数。
3.按照在类定义中出现的顺序,对派生类中新增的成员对象进行初始化。对于类类型的成员对象,如果出现在构造函数初始化列表中,则以其中指定的参数执行构造函数。如果未出现,则执行默认构造函数;对于基本数据类型的成员对象,如果出现在构造函数的初始化列表中,则使用其中指定的值为其赋初值,否则什么页不做。
4.执行构造函数的函数体。