目录
继承的定义:
继承方式:
继承中的细节问题:
继承的定义:
当我们要写多个类时,如果一个类A中需要包含另外一个类B的属性,我们可以用到继承的 *** 作,让A继承B的属性,即会让A增多一些B中才有的属性,继承后A中有B的属性,同时A中也会有一些自己增加的属性。A称为子类,派生类;B称为父类,基类。使用继承可以避免很多重复的代码,可以有效减少代码冗余。
继承的语法是:
class + 派生类 + 继承方式 + 父类
下面是一个例子:父类的成员,子类通过继承后也可以增加对应的成员。
class Fath
{
public:
void Output2()
{
cout << "This is Fath" << endl;
}
private:
int a = 10;
};
class Son:public Fath
{
public:
void Output()
{
cout << "This is Son" << endl;
}
};
int main()
{
Son A;
A.Output();
A.Output2();
return 0;
}
继承方式:
派生类继承基类的方式有三种:公共继承、私有继承、保护继承。这三种继承方式对于派生类所继承到的基类成员在派生类中的权限不同。注意:三种继承方式都无法继承父类中的私有成员。
1.公共继承:
子类可以继承父类公共权限和保护权限下的成员,而继承后,原先在父类中是公共权限的成员,在子类中也为公共权限;而在父类中为保护权限的成员在子类中为保护权限。
//公共继承方式:
class Fath
{
public:
int a;
protected:
int b;
private:
int c;
};
class Son : public Fath
{
public:
Son()
{
//公共权限:
a = 20;
//保护权限:
b = 30;
}
};
int main()
{
Son s1;
cout << s1.a << endl;
//不可访问!
//cout << s1.b << endl;
return 0;
}
2.保护继承:
子类可以继承父类公共权限和保护权限下的成员,而继承后,原先在父类中是公共权限的成员,在子类中也为保护权限;而在父类中为保护权限的成员在子类中仍为保护权限。
//保护继承方式:
class Fath
{
public:
int a;
protected:
int b;
private:
int c;
};
class Son : protected Fath
{
public:
Son()
{
//保护权限:
a = 20;
//保护权限:
b = 30;
}
};
int main()
{
Son s1;
//两个都是子类保护权限下的子类内容,类外无法访问!
//cout << s1.a << endl;
//cout << s1.b << endl;
return 0;
}
2.私有继承:
子类可以继承父类公共权限和保护权限下的成员,而继承后,原先在父类中是公共权限的成员,在子类中也为私有权限;而在父类中为保护权限的成员在子类中仍为私有权限。
//私有继承方式:
class Fath
{
public:
int a;
protected:
int b;
private:
int c;
};
class Son : private Fath
{
public:
Son()
{
//私有权限:
a = 20;
//私有权限:
b = 30;
}
};
class Grandson :public Son
{
public:
Grandson()
{
//Son类从Fath那里继承的成员在Son类中变成Son类的私有成员,Grandson不可访问!
//a = 20;
//b = 30;
}
};
int main()
{
Son s1;
Grandson s2;
return 0;
}
总结起来三种继承方式,不同的继承方式对于子类从父类那里继承过来的成员在子类中的权限不同。
公共继承--父类中的公共权限在子类中变成公共权限,父类中的保护权限在子类中变成保护权限;
保护继承--父类中的公共权限在子类中变成保护权限,父类中的保护权限在子类中变成保护权限;
私有继承--父类中的公共权限在子类中变成私有权限,父类中的保护权限在子类中变成私有权限;
但是无论是哪种继承方式,子类都无法继承父类的私有成员!
继承中的细节问题:1.继承中的析构和构造函数调用顺序问题:先调用父类构造函数,再调用子类构造函数,然后调用父类析构函数,最后调用子类析构函数。
2.继承的原理问题:子类继承父类其实是将父类中所有的非静态成员都继承了,只不过我们编译器隐藏了private权限下的成员,所以如果我们对子类求大小,就会发现其实子类是包含了父类中所有的非静态成员。
3.继承中的同名问题:如果子类和父类都有相同的属性名称,那么我们访问子类的属性直接访问即可,但是访问从父类那里继承的需要加上作用域!相似的,如果子类和父类具有相同名称和函数成员,那么要想访问从父类那里继承的函数成员也是需要加作用域!注意,只要函数名称相同,函数重载也不能作为区分是从父类那里继承的成员函数还是子类自己有的成员函数的条件。
4.静态同名成员问题:对于静态的成员变量,我们一般可以通过类名或者对象名来访问。如果继承中出现同名静态成员,通过对象名访问方式和上面一样;但是通过类名访问方式需要我们在前面多加作用域。
//通过类名访问:
class Fath
{
public:
static int a;
};
int Fath:: a = 10;
class Son: public Fath
{
public:
static int a;
};
int Son::a = 20;
int main()
{
Son A;
cout<
5.多继承问题:多继承问题即一个子类可以继承多个父类,它的基本语法是:
class 子类 :继承方式+父类1,继承方式2+父类2.....
相似的,我们应对父类同名问题也可以使用作用域区分,不过现实生活中不建议使用多继承语法。
6.虚继承问题:虚继承问题对应的是一个子类从两个父类中继承的是一样的成员(此时两个父类都在一个父类中继承了一样的数据),那么此时子类中就会有两份重复的数据,为了解决这个问题,我们采用虚继承。虚继承实现就是在两个父类public前加上关键字vitrual
class Base
{
public:
int age;
};
class P_base1 : virtual public Base{};
class P_base2 : virtual public Base{};
class Son :public P_base1, public P_base2{};
int main()
{
Son A;
return 0;
}
采用了关键字后,Son中继承的只有一份数据,并且从两个父类中分别继承一个各自的指针vbptr,这个vbptr指向一个各自的vbtable表,这个表中记录了各自的偏移量,并且各自可以通过偏移量找到同一份数据。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)