继承概念:通过继承机制,可以利用已有的数据类型来定义新的数据类型,新的数据类型不仅拥有新定义的成员,而且同时还拥有旧的成员。我们称已存在的用来派生新类的类称为基类(父类),派生出来的新类称为派生类(子类)。继承提高了代码的复用率
一.继承格式
二.继承方式:
1.公有继承(public)
公有继承特点:基类的公有成员,和保护成员,私有成员作为派生类的成员时,他们 都保持原有的状态。也就是说基类的私有成员,派生类中仍然是私有的,不能被这个派生类子类访问。
2.私有继承(private)
私有继承的特点:基类的公有成员私有成员,保护成员都作为派生类的私有成员。并且全都不能被这个派生类子类访问
3.保护继承(protected)
保护继承的特点:基类的公有成员,保护成员都作为派生类的保护成员,可以被派生类的子类访问。基类的私有成员仍作为派生类私有成员,不能被派生类子类访问
以上三种继承方式在其成员可见性方面的问题
公有继承方式
(1)基类成员对其对象可见性:public可见,其他不可见(这里protected相当于private)
(2)基类成员对其派生类可见性:public 和protected可见,private不可见
(2)基类成员对派生类对象可见性:public可见,其他不可见
私有继承方式
(1)基类成员对其对象可见性:public可见,其他不可见(这里protected相当于private)
(2)基类成员对其派生类可见性:public 和protected可见,private不可见
(2)基类成员对派生类对象可见性:所有成员都是不可见的
保护继承方式
(1)基类成员对其对象可见性:public可见,其他不可见(这里protected相当于private)
(2)基类成员对其派生类可见性:public 和protected可见,private不可见
(2)基类成员对派生类对象可见性:所有成员都是不可见的
为了验证上述结论请看下面例子
公有继承:
class Parent//父类
{
private:
int a;
public:
int b;
protected:
int c;
};
class Child :public Parent//公有继承
{
private:
public:
void fun()//派生类成员访问基类
{
a = 10;//no
b = 10;//yes
c = 10;//yes
}
protected:
};
int main()
{
Parent e;//基类对象访问基类成员
e.a = 10;//no
e.b = 10;//yes
e.c = 10;//no
Child d;//派生类对象访问基类成员
d.a = 10;//no
d.b = 10;//yes
d.c = 10;//no
}
私有继承:
class Parent//父类
{
private:
int a;
public:
int b;
protected:
int c;
};
class Child :private Parent//私有继承
{
private:
public:
void fun()//派生类成员访问基类
{
a = 10;//no
b = 10;//yes
c = 10;//yes
}
protected:
};
int main()
{
Parent e;//基类对象访问基类成员
e.a = 10;//no
e.b = 10;//yes
e.c = 10;//no
Child d;//派生类对象访问基类成员
d.a = 10;//no
d.b = 10;//no
d.c = 10;//no
}
保护继承:
class Parent//父类
{
private:
int a;
public:
int b;
protected:
int c;
};
class Child :protected Parent//私有继承
{
private:
public:
void fun()//派生类成员访问基类
{
a = 10;//no
b = 10;//yes
c = 10;//yes
}
protected:
};
int main()
{
Parent e;//基类对象访问基类成员
e.a = 10;//no
e.b = 10;//yes
e.c = 10;//no
Child d;//派生类对象访问基类成员
d.a = 10;//no
d.b = 10;//no
d.c = 10;//no
}
三.继承与转换——赋值兼容规则——public继承
1.子类对象可以赋给父类对象//切片,切割
2.父类对象不可赋给子类对象
3.父类的指针/引用可以指向子类对象//切片,切割
4.子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)容易产生越界访问
以下给出代码
四:派生类默认成员函数
在继承关系中,派生类如果没有显示定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数
继承关系中构造函数调用顺序
先执行派生类构造函数,在派生类构造函数初始化列表调用-----------基类构造函数--------------------接着执行派生类构造函数体
验证我们上面的结论给出代码:
class A
{
public:
A(int a)
:_a(a)
{
cout << "A(int a)" << endl;
}
A(const A& a)
{
cout << "A(const A& a)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
public:
int _a;
};
class B:public A
{
public:
B(int a, int b)
:A(a)
,_b(b)
{
cout << "B(int a,int b)" << endl;
}
B( B& b)
:A(b)//切片,切割
,_b(b._b)
{
cout << "B( B& b)" << endl;
}
public:
int _b;
};
int main()
{
//A a(3);
//A a1(a);
//B b(3,4);
B b(3,4);
//B b2(b);
system("pause");
}
结果:
继承关系中析构函数调用顺序
先调用派生类析构函数-----------------再(自动)调用基类析构函数
五:继承体系中的作用域
1.在继承体系中基类和派生类是两个不同作用域
2.子类和父类中有同名成员(包括成员变量,和成员函数),子类成员将屏蔽父类对成员直接访问(在子类函数中,可以使用基类::基类成员 访问)//也叫隐藏,重定义
六:友元关系不能继承,也就是说基类有元不能访问子类私有和保护成员
直接看例子
class Student;
class Person
{
public:
Person(int a=2)
:_a(a)
{}
friend void Display(Person& p, Student& s);
private:
int _a;
};
class Student : public Person
{
protected:
int _b;
};
void Display(Person& p, Student& s)
{
cout << p._a << endl;
cout << s._b<< endl;//友元不能被继承,基类友元不能访问子类私有和保护成员
};
int main()
{
Person p;
Student s;
Display(p, s);
system("pause");
return 0;
}
七:单继承,多继承,菱形继承
1.单继承:一个子类只有一个直接父类时称这个继承关系为单继承。
2.多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
3.菱形继承:就是综合了单继承,和多继承
想必大家对此都有了解,于是概念就不多说了。
菱形继承存在的问题:二义性,和数据冗余
class A
{
public:
int _a;
};
class B:public A
{
public:
int _b;
};
class C :public A
{
public:
int _c;
};
class D :public B, public C
{
public:
int _d;
};
int main()
{
B b;
C c;
D d;
//d._a//不知道访问父类B,和父类C中哪个//即二义性
d.B::_a = 4;
d.C::_a = 5;//以上两行代码说明了_a有两份,体现了数据冗余
}
那么如何解决数据冗余和二义性问题呢?虚继承就解决了这个问题
八:虚继承
虚继承就是指在菱形继承中将基类的数据只继承了一份。
class A
{public:
int _a;
};
class B:virtual public A//虚继承就是在B和C继承A时,前面加virtual
{
public:
int _b;
};
class C:virtual public A//虚继承就是在B和C继承A时,前面加virtual
{
public:
int _c;
};
class D :public B, public C
{
public:
int _d;
};
//对象模型——内存当中的分布
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
//cout << sizeof(d) << endl;//20不加virtual
cout<<sizeof(d) << endl;//24加virtual
}
按理说既然继承了一份,那么就应该大小是16,为什莫是24呢?
请看下图解释的很清楚: