继承
继承是复用已经定义的操作,使前者所有的特性在后者中自动可用。
每一层都是对上一层的细化。
类型继承是oop的精华之一。
继承的方式
可以继承父类中的private成员,但是子类是无法访问的
继承的三种方式:
- 公有继承,那么子类拿到的父类public和protected还放到自己的public和protected。
- 保护继承,子类拿到父类的都放到自己的protected。
- 私有继承,子类拿到父类的都放到自己的private。
#include <iostream>
using namespace std;
class Father
{
public:
int a;
protected:
int b;
private:
int c;
};
class Son : public Father
{
public:
void func()
{
cout << a << endl; // father中public但是是用protected方式继承来的。
cout << b << endl;
//cout << c << endl; 继承不到
}
};
int main()
{
Son son;
//son.a; 访问不了,因为在子类中是protected的。
}
一般继承都是public继承。protected和private实际中使用很少。
继承中构造和析构
派生类对象中包含从基类继承来的成员,但是他不能直接初始化这些成员,必须调用基类构造函数来初始化他。
也就是每个类控制自己的初始化过程。
#include <iostream>
using namespace std;
class Father
{
public:
Father()
{
cout << "父类构造" << endl;
}
~Father()
{
cout << "父类析构" << endl;
}
};
class Son : protected Father
{
public:
Son()
{
cout << "子类构造" << endl;
}
~Son()
{
cout << "子类析构" << endl;
}
};
int main()
{
Son son;
}
/*
父类构造
子类构造
子类析构
父类析构
*/
当父类中没有无参构造
#include <iostream>
using namespace std;
class Father
{
public:
Father(int a)
{
cout << "父类构造" << endl;
}
~Father()
{
cout << "父类析构" << endl;
}
};
class Son : public Father
{
public:
//子类要先调用父类无参构造。但是父类没有无参构造,这时子类会报错
//解决方法:显示调用父类自定义的有参构造。
Son(int b): Father(b) //子类这个数直接也传给父类进行初始化
{
cout << "子类构造" << endl;
}
~Son()
{
cout << "子类析构" << endl;
}
};
int main()
{
Son son(5);
}
/*
父类构造
子类构造
子类析构
父类析构
*/
继承的成员变量
如果子类只是继承父类的变量,则在子类中该变量其实只有一个,他的名字可以叫 d.A::n d.B::n 或 d.n,他们三个都是一个人
class A
{
public:
int n;
};
class B: public A {};
class D: public B {};
int main()
{
D d;
d.A::n = 10;
d.B::n = 20;
d.n = 30;
cout<< d.n << ", "<< d.B::n << ", " << d.n<< endl; //30,30,30
}
如果子类中重新定义了父类继承来的变量,那么子类中其实存在父类变量,也就是如下中D中存在三个变量,分别对应三个值
class A
{
public:
int n;
};
class B: public A {
public:
int n;
};
class D: public B {
public:
int n;
};
int main()
{
D d;
d.A::n = 10;
d.B::n = 20;
d.n = 30;
cout<< d.A::n << ", "<< d.B::n << ", " << d.n<< endl;//10,20,30
}
函数继承同上
多重继承
子类继承父类变量,多重继承
class A
{
public:
int n;
};
class B: public A {};
class C: public A {};
class D: public B ,public C{ };
int main()
{
D d;
//d.n = 1;//直接拿n会报错,因为这里存在二义性,不知道是从B拿来的还是从C拿来的
//d.A::n = 4; //这里会报错,因为是多重继承,所以这里的A会产生歧义,不知道是从B拿来的A还是从C拿来的A
d.B::n = 10; //这里就可以,因为明确说明n
d.C::n = 20;
}
使用虚基类解决多继承问题
class A
{
public:
int n;
};
class B: virtual public A {};
class C: virtual public A {};
class D: public B ,public C{ };
int main()
{
D d;
//d.n = 1; //可以拿到
//d.A::n = 4; //可以拿到,只有一个n
d.B::n = 10;
d.C::n = 20;
cout << d.A::n;
}
它的被继承成员在派生类中只保留一个实例。从类 D这个角度上来看,它是从类B与类C继承过来的,而类B C又是从类A继承过来的,
但它们只保留一个副本。因此在子类中实际只有唯一的该变量
所以设计类时避免多重继承,并且没有证明哪种设计是必须采用多重继承的。