一、继承方式和权限问题:
父类(继承中) 基类(派生)->子类 派生类
实质:父类的数据成员子类中也有一份。
注:父类的私有属性能够被子类继承下来,但是不可以直接被访问(即通过接口访问是可以的,在父类中写一个接口函数)
写法:
class parent{};
class 子类名 : 继承方式 父类名{}
其中的继承方式就是 三种权限限定。
权限问题:继承方式只会增强父类属性在子类中的权限显示。
(以下表格默认是直接访问)
注意:最后一行,private是在子类中的私有,在子类中,仍可以直接访问。而“不可直接访问”是父类的私有,无论何时都不可以直接访问(私有继承容易“断了血脉”,因为再继承无法再有任何作用)。
二、继承中的构造函数:
①父类的属性需要通过父类的构造函数去初始化。
②子类中的构造函数,必须调用父类构造函数(注意区分类的组合的写法(初始化列表用的是对象名),此处直接用类名),必须采用初始化参数列表的方式(这是子类,父类爱咋写咋写)
注:1.子类构造对象,优先调用父类构造函数。
2.Son(){ }这种写法,父类必须存在无参的构造函数,当然缺省也可以。
③单继承和多继承
1.单继承:只有一个父类
2.多继承(吕布):两个or两个以上的父类
例:“阳子”与“欧田”
#include<iostream>
#include<string>
using namespace std;
class a
{
public:
a(string mmFname,string mmSname):mmFname(mmFname), mmSname(mmSname){}
protected:
string mmFname;
string mmSname;
};
class b
{
public:
b(string mmFname, string mmSname) :ggFname(mmFname), ggSname(mmSname) {}
protected:
string ggFname;
string ggSname;
};
class daughter:public a,public b
{
public:
daughter(string mmFname, string mmSname, string ggFname, string ggSname) :a(mmFname, mmSname), b(ggFname, ggSname)
{
daFname = mmFname + ggFname;
daSname = mmSname + ggSname;
}
void print()
{
cout << "妈妈:" + mmFname + mmSname << endl;
cout << "爸爸:" + ggFname + ggSname << endl;
cout << "女儿:" + daFname + daSname << endl;
}
protected:
string daFname;
string daSname;
};
int main()
{
daughter wbm("阳", "子", "欧", "田");
wbm.print();
return 0;
}
④继承的属性,无论被继承多少次一直都是在的,所以类一般不会被继承很多层(3),会导致类的臃肿。
三、继承中同名问题:
1.数据成员同名、成员函数同名以及正常的赋值指针调用:不做特殊处理,遵循就近原则
(子类中print子类数据成员)
想调用远的?解决:加上类名限定::
2.非正常指针:①允许子类对象初始化父类指针
MM* pMM=new girl("newgirl",19);
pMM->print();
//MM是父类 girl是子类
无virtual,看指针类型。
有virtual,看赋值对象
(即若girl在继承的时候没有写 virtual public MM,那么这边同名就调用的是指针类型pMM的print(),若写了virtual,则是girl的print())
无virtual
#include<iostream>
using namespace std;
class A
{
public:
A(int a,int b):a(a),b(b) {}
void print()
{
cout << a << endl;
}
protected:
int a;
int b;
};
class B:public A
{
public:
B(int a,int b1,int b2):A(a,b1),b(b2) {}
void print()
{
cout << a << "\t" << b << endl;
}
protected:
int b;
};
int main()
{
B b(1, 2,3);
b.print();//测试:1.会调用哪个print()2.会用哪个b?
B* wbm = new B(1, 2, 3);//正常指针调用
wbm->print();//测试2
A* gzj = new B(1, 2, 3);
gzj->print();//测试3
return 0;
}
有virtual
#include<iostream>
using namespace std;
class A
{
public:
A(int a,int b):a(a),b(b) {}
void print()
{
cout << a << endl;
}
protected:
int a;
int b;
};
class B:virtual public A
{
public:
B(int a,int b1,int b2):A(a,b1),b(b2) {}
void print()
{
cout << a << "\t" << b << endl;
}
protected:
int b;
};
int main()
{
B b(1, 2,3);
b.print();//测试:1.会调用哪个print()2.会用哪个b?
B* wbm = new B(1, 2, 3);//正常指针调用
wbm->print();//测试2
A* gzj = new B(1, 2, 3);
gzj->print();//测试3:非正常赋值调用,看赋值类型即B 此处调用的是B的print()
return 0;
}
3.虚继承-----"菱形继承"
以上这种情况,会出现两个a所以D该用哪个a?
1.用virtual继承由A继承到B和C ,此后a仅由祖父类决定,与BC类无关(尽管加类名限定也无效)(a始终保持一份!)。
2. D写初始化参数成员列表必须调用祖父类的构造函数
#include<iostream>
using namespace std;
class A
{
public:
A(int a):a(a) {}
void print()
{
cout << a << endl;
}
int a;
};
class B:virtual public A
{
public:
B(int a,int b):A(a),b(b) {}
int b;
};
class C :virtual public A
{
public:
C(int a, int c) :A(a), c(c) {}
protected:
int c;
};
class D :public B, public C
{
public:
D():B(2,3),C(4,5),A(666){}
void print()
{
cout << a << endl;
cout << B::a << endl;
cout << C::a << endl;
}
protected:
};
int main()
{
D d;
d.print();
return 0;
}
“只有一份a”
四、构造和析构顺序问题
1.单继承构造:先构造父类的(无论写不写初始化参数列表),再构造子类的=>析构顺序相反
#include<iostream>
using namespace std;
class A
{
public:
A(int a) :a(a) { cout << "A"; }
~A()
{
cout << "A";
}
protected:
int a;
};
class B:public A
{
public:
B(int a, int b) :A(a), b(b) { cout << "B"; }
~B()
{
cout << "B";
}
protected:
int b;
};
int main()
{
B b(1,2);
return 0;
}
//ABBA
2.多继承构造:①任何构造顺序问题,都和初始化参数列表无关
②构造顺序和开头所写的继承顺序一致。
#include<iostream>
using namespace std;
class A
{
public:
A(int a) :a(a) { cout << "A"; }
~A()
{
cout << "A";
}
protected:
int a;
};
class B
{
public:
B(int b) : b(b) { cout << "B"; }
~B()
{
cout << "B";
}
protected:
int b;
};
class C
{
public:
C(int c) : c(c) { cout << "C"; }
~C()
{
cout << "C";
}
protected:
int c;
};
class D :public B, public A, public C
{
public:
D(int d = 0) :A(2), B(1), C(321), d(d) { cout << "D"; }
~D()
{
cout << "D";
}
protected:
int d;
};
int main()
{
D d;
return 0;
}
与参数列表的顺序无关!
练习:
1. 设计一个类父类 Shape类 设计多个子类:Rect类 Circle类 分别求出并打印相应形状的周长和面积
2.设计类老师类,设计一个学生类,多继承产生一个研究生类,打印相关研究生的信息