继承(C++) 下

简介: 继承(C++)

继承与友元


友元关系不能继承,基类友元不能访问派生类私有和保护成员


class Person
{
public:
  friend void Display(const Person& p,const Student s);
  Person(const char* name = "zhangsan")
  :_name(name)
  {
  cout << "Person()" << endl;
  }
protected:
  string _name;
};
class Student :public Person
{
public:
  Student(const char* name)
  :Person(name)
  , _stuid(210202)
  {
  cout << "Student()" << endl;
  }
protected:
  int _stuid;
};
void Display(const Person& p,const Student s)
{
  cout << p._name << endl;
  cout << s._stuid << endl;
}
int main()
{
  Person p("zhangsan");
  Student s("lisi");
  Display(p,s);
  return 0;
}


4968cb4015348ff59c1914e542029747_ea4dd0e9eed3416fa964b1d3bdb6bdc9.png


继承与静态成员


如果基类定义了static静态成员,则整个继承体系里面只有一个这样的成员


class Person
{
public:
  Person()
  {
  ++_count;
  }
protected:
  string _name;
public:
  static int _count;//统计人数
};
int Person::_count = 0;
class Student :public Person
{
protected:
  int _stuid;
};
int main()
{
  Person p;
  Student s;
  p._count++;
  cout << p._count << endl;
  cout << &p._count << endl;
  s._count++;
  cout << s._count << endl;
  cout << &s._count << endl;
  return 0;
}


57dc67466dda16a0ee62bd59c3f55e24_07c4147562da4117954d49f6fcc9674d.png


打印的地址都一样,说明static成员,并不在类中,而是存储在静态区中的;静态成员属于整个类,所有对象,同时也属于所有派生类及对象


复杂的菱形继承及菱形虚拟继承


单继承:一个子类只有一个直接父类的继承关系


e23de166ee24272df6f3bde621e4d9a4_dc198e218f494e7080d1f2f6fe20776f.png


多继承:一个子类有两个或者以上直接父类的继承关系


18f2c5a34a5da10863ea34d3cc253c14_65006a67a2ab4600aa9f93ca23a96e67.png


菱形继承:多继承的一种


811f3ad8a662843e64df66896a9a6535_9c658db97f1441fbae2c68f3de64984f.png


菱形继承存在着某些问题,观察下列代码


class Person
{
public:
  string _name;
};
class Student :public Person
{
protected:
  int _stuid;
};
class Teacher :public Person
{
protected:
  int _jodid;
};
class Assistant :public Teacher, public Student
{
protected:
  string _majorcourse;
};
int main()
{
  Assistant a;
  a._name = "zhangsan";
  return 0;
}


90b5ba3918dd7bce96e445816dd535ef_b12cd676757c4fd1a59b8c25995722ce.png


程序运行之后便会报错,因为Assistant a中有两份_name,一份是Student,一份是Teacher的,所以使用时就造成了二义性;解决方式:使用时加上访问限定符


int main()
{
  Assistant a;
  a.Student::_name = "zhangsan";
  a.Teacher::_name = "lisi";
  return 0;
}


指定作用域并没有彻底地解决菱形继承所造成的问题,接下来介绍虚拟继承来彻底地解决问题


在 Student和 Teacher中继承 Person时使用虚拟继承


51d6e1e6ae03d10acfc1b43d43d66a76_dd19d605d5f345ab9a0c209763301bbb.png


具体操作如下


class Person
{
public:
  string _name;
};
class Student :virtual public Person
{
protected:
  int _stuid;
};
class Teacher :virtual public Person
{
protected:
  int _jodid;
};
class Assistant :public Teacher, public Student
{
protected:
  string _majorcourse;
};
int main()
{
  Assistant a;
  a._name = "zhangsan";
  return 0;
}


0d7c334e0d7a04fd0a6a62787319ec19_d549cd4b73f44670a3cb616004bb0058.png


既然已经知道虚拟继承可以解决菱形继承存在的问题,那么原理是什么呢?要做到知其然知其所以然,接下来就深入学习虚拟继承的原理


虚拟继承的原理


观察下列代码

菱形继承:


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()
{
  D d;
  d.B::_a = 1;
  d.C::_a = 2;
  d._b = 3;
  d._c = 4;
  d._d = 5;
  return 0;
}


通过查看内存,可以很清楚地发现数据冗余


5441f564580d0be187afd898a0a1aaa1_192a45a09913401fb24c0bdeb0b48a74.png


菱形虚拟继承:


class A
{
public:
  int _a;
};
class B :virtual public A
{
public:
  int _b;
};
class C :virtual public A
{
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;
  return 0;
}


6a0ce7560050bda1552a63e3193c5fb2_2e1aeee1064e43e7b98148d897e3a3ab.png


通过查看内存,B和C中都存在一个指针,分别对指针进行取地址发现,指针所指向的是虚基表,其中保存着距离虚基类对象_a的偏移量(第二行),通过偏移量可以计算出B和C中虚拟继承的_a的位置,在上面已经标注出来。


虚拟继承原理解释如下


b2c70fca835ebccbcac1262488fa53da_421e50b5dff947bfb687ed0a520af6f7.png


继承和组合

  1. public继承是一种is a的关系,每个派生类对象中都是一个基类对象
  2. 组合是一种has a的关系,比如B组合了A,则每个B对象中都有一个A对象


目录
相关文章
|
19天前
|
Java C++
C++的学习之路:21、继承(2)
C++的学习之路:21、继承(2)
18 0
|
2月前
|
C++
8. C++继承
8. C++继承
27 0
|
2月前
|
安全 程序员 编译器
C++之继承
C++之继承
|
3天前
|
安全 前端开发 Java
【C++】从零开始认识继承二)
在我们日常的编程中,继承的应用场景有很多。它可以帮助我们节省大量的时间和精力,避免重复造轮子的尴尬。同时,它也让我们的代码更加模块化,易于维护和扩展。可以说,继承技术是C++的灵魂。
10 1
|
3天前
|
安全 程序员 编译器
【C++】从零开始认识继承(一)
在我们日常的编程中,继承的应用场景有很多。它可以帮助我们节省大量的时间和精力,避免重复造轮子的尴尬。同时,它也让我们的代码更加模块化,易于维护和扩展。可以说,继承技术是C++的灵魂。
19 3
【C++】从零开始认识继承(一)
|
19天前
|
安全 编译器 程序员
c++的学习之路:20、继承(1)
c++的学习之路:20、继承(1)
29 0
|
2月前
|
安全 Java 编译器
C++:继承
C++:继承
32 0
|
2月前
|
安全 Java 程序员
【C++练级之路】【Lv.12】继承(你真的了解菱形虚拟继承吗?)
【C++练级之路】【Lv.12】继承(你真的了解菱形虚拟继承吗?)
|
2月前
|
安全 Java 编译器
C++:继承与派生
C++:继承与派生
|
1天前
|
存储 编译器 C++
C++中的继承
C++中的继承
9 0