父类中的属性:
调用父类的构造函数初始化
成员函数的方式初始化
子类中的构造函数:
必须要调用父类构造函数
必须采用初始化参数列表的方式
class Parent
{
public:
/*我们写了构造函数,默认的构造函数就不存在了,子类构造函数报错
Parent(string FName,string SName):FName(FName),SName(SName){}*/
Parent() { cout << "父类无参构造函数" << endl; }
protected:
string FName; //姓
string SName; //名
};
//单继承
class Son :public Parent
{
public:
/*对于子类,必须采用初始化参数列表的方式,如果想构造无参对象,且不想采用初始化参数列表
的方式,父类中必须存在无参的构造函数,当然缺省也可以*/
Son() { cout << "子类无参构造函数" << endl; }
protected:
string sonFName;
string sonSName;
/*string FName; 子类继承父类属性的权限
string SName;*/
};
int main()
{
//子类构造对象,优先调用父类构造函数,再调用自己的构造函数
Son son; //初始化参数列表的隐式写法
return 0;
}
/*输出*/
父类无参构造函数
子类无参构造函数
例:父类姓名"小白",子类继承父类的姓"小",子类的名为"黑"--->子类姓名"小黑"
class Parent
{
public:
//需要写两个参数的构造函数
Parent(string FName, string SName) :FName(FName), SName(SName)
{
cout << "父类有参构造函数" << endl;
}
protected:
string FName; //父姓
string SName; //父名
};
//单继承
class Son :public Parent
{
public:
/*传参随意,不传变量FName|直接传常量初始化FName也可以|参数从哪里传进来无所谓
只要类型|个数和父类构造函数一致就行了,可以不使用,但是必须要传
Son(string FName, string SName, string sonSName) :Parent("k", SName)
{
}
*/
Son(string FName, string SName, string sonSName) :Parent(FName, SName)
{
//自己的属性用什么方式初始化都行 this指针|初始化参数列表
this->sonFName = FName; //子姓和父亲姓相同,继承父亲姓即可
this->sonSName = sonSName; //自己的名
cout << "子类有参构造函数" << endl;
}
void print() //父类属性不是private属性,可以直接访问
{
cout << "父:" << FName + SName << endl;
cout << "子:" << sonFName + sonSName << endl;
}
protected:
string sonFName; //子姓
string sonSName; //子名
/*string FName; 父类中属性在子类中的权限是保护类型
string SName; 必须调用父类的构造函数初始化*/
};
int main()
{
Son son("小","白","黑"); //子类构造对象,优先调用父类构造函数,再调用自己的构造函数
son.print();
return 0;
}
/*输出*/
父类有参构造函数
子类有参构造函数
父:小白
子:小黑
继承--->类名
类的组合--->对象名
单继承: 只有一个父类的继承关系
多继承: 两个或者两个以上的父类的继承关系
无论是单继承还是多继承都必须调用父类的构造函数
//多继承
//父:欧田
//母:阳子
//女:姓:欧阳 名:田子
class MM
{
public:
//MM() = default;
MM(string mmFName, string mmSName) //父类没有继承产生子类前,怎么初始化都可以
{
this->mmFName = mmFName;
this->mmSName = mmSName;
}
protected:
string mmFName;
string mmSName;
};
class GG
{
public:
//GG() = default;
GG(string ggFName, string ggSName)
{
this->ggFName = ggFName;
this->ggSName = ggSName;
}
protected:
string ggFName;
string ggSName;
};
//继承GG&MM类,可以是不同权限,只是父类中的属性在子类中的权限不同
class Girl :public GG,public MM
{
public:
//子类想要构造无参对象,每个父类都要有一个无参构造函数
//Girl() {} //继承的属性必须采用初始化参数列表的方式调用父类构造函数初始化
Girl(string mmFName, string mmSName, string ggFName, string ggSName)
:MM(mmFName,mmSName),GG(ggFName,ggSName)
{
girlFName = ggFName + mmFName;
girlSName = ggSName + mmSName;
/*girlFName = GG::ggFName + MM::mmFName;
girlSName = GG::ggSName + MM::mmSName;*/
}
void print()
{
cout << "父:" << ggFName + ggSName << endl; //继承下来的属性
cout << "母:" << mmFName + mmSName << endl;
cout << "女:" << girlFName + girlSName << endl;
}
protected:
string girlFName;
string girlSName;
};
//测试
int main()
{
Girl girl("阳", "子", "欧", "田");
girl.print();
return 0;
}
/*输出*/
父:欧田
母:阳子
女:欧阳田子
继承的属性一直都在,无论被继承多少次,所以类一般不会被继承很多层,继承次数过多会导致类的臃肿,这里还没有算入方法,如果每一个类中都有方法,D类的方法就太多了
//继承的属性一直都存在,无论被继承多少次
class A
{
public:
A(int a) :a(a) {}
int a;
};
class B:public A //A类产生子类B类
{
public: //A的属性用A的构造函数初始化,B的属性用初始化参数列表初始化
B(int a,int b) :A(a),b(b) {}
int b; //增加一个属性b
};
class C :public B //B类产生子类C类
{
public: //A类的属性还存在,C类需要为B类的数据成员和A类的数据成员初始化
C(int a, int b,int c) :B(a,b),c(c) {}//直接调用B的构造函数即可,不用调用A的
int c; //增加一个属性c
};
class D :public C //C类产生子类D类,类的属性越来越多
{
public:
D(int a, int b, int c,int d) :C(a,b,c), d(d) {}
int d; //增加一个属性d
};
关于继承中的构造和析构顺序问题可以看看这篇博客:c++继承-----继承中的构造和析构顺序问题_考拉爱睡觉鸭~的博客-CSDN博客