引言
这篇博客本来在上个月就应该发出来,但是中间由于各种原因,而一拖再拖,今天也终于完成了这篇博客, 各位看官请好好欣赏吧
继承的概念与定义
继承是对代码进行复用,是类设计层次的复用,让我们的子类可以使用父类的代码,减少代码的冗余提高效率
class strudent
{
string name;
string id;
string address;
}
class teacher
{
string name;
string id;
string address;
}
我们会发现这虽然这是两种不同的类,但是有很多信息是重复冗余的 所以我们完全可以定义个父类,来保存共有的信息
如:
class person
{
string name;
string id;
string address;
}
继承person的
class student:public person
{
private:
}
class teacher:public person
{
private:
}
#include<iostream>
using namespace std;
class Person
{
public:
void Print()
{
cout << "name:" << _name << endl;
cout << "age:" << _age << endl;
}
protected:
string _name = "peter";
int _age = 18;
};
class Student : public Person
{
protected:
int _stuid;
};
class Teacher : public Person
{
protected:
int _jobid;
};
int main()
{
Student s;
Teacher t;
s.Print();
t.Print();
return 0;
}
继承的模板
class student :public person
继承的定义
class默认是公有继承(但是我们最好把继承方式写上)
- 格式
class student :public person student是派生类,public是继承方式,person是基类 - 继承关系与访问限定符
继承方式 :public继承,protect继承,private继承 访问限定符 :public访问,protect访问,private访问
- 基类的private成员在派生类中无论以什么方式继承都是不可以见到的
数据继承下来了,在那个地方但是用不上,不可以见的意思是 :继承下来之后,不管是在类的里面还是在类的外面都不可以访问他 继承:简单粗暴,直接全部继承下来,但是无论如何都永不上这个成员的
不想给子类用就定义成private,想给子类用就定义成public或者protected
-
取访问限定符和访问方式中的小的那一个 public>protect>private -
public和protect和private的区别 public想让别人可以直接使用 protect不想要让别人直接使用,但是想要让子类能够使用 private不想让任何人使用,包括子类
保护和私有在父类中没有区别
4.在实际使用的过程中,一般都是public继承,几乎很少private和protect,不提倡private和protect继承, 在类里面基本都使用protect和public,几乎不使用private
常见的继承 父类成员:公有和保护 子类继承方式:公有继承
基类和派生类对象赋值转换
(赋值兼容规则) 我们以前学过,如果是同一种类型就可以直接进行赋值,如果不是同一种类型可以实现显示类型访问,
如果我们想要子类给父类
class person
{
protected:
string _sex;
string _name;
int _age;
};
class student : public person
{
public:
int _no;
};
int main()
{
person p;
student s;
p=s;
person*ptr=&s;
person& ref=s;
return 0;
}
继承中的作用域
- 在继承体系中基类和派生类偶有独立的作用域
子类和父类出现同名成员:隐藏/重定义,子类会隐藏父类的同名成员 如果有同一名字的话,并不是构成函数重载(重载是在同一个作用域里面才可以称之为重载) 只要函数名相同就构成隐藏,参数的相同与否无所谓,不影响 最好不用定义同名的成员函数和同名成员
class student : public person
{
public:
int _no = 1;
void Print()
{
cout << _no;
cout << person::_no << endl;
}
};
int main()
{
person p;
student s;
s.Print();
s.person::Print();
return 0;
}
派生类的默认成员函数
#include <string>
#include<iostream>
using namespace std;
class Person
{
public:
Person(const char *name )
: _name(name)
{
cout << "person()" << endl;
}
Person(const Person &s)
: _name(s._name)
{
cout << "person(const person& s)" << endl;
}
Person &operator=(const Person &s)
{
cout << "Person=" << endl;
if (this != &s)
{
_name = s._name;
}
return *this;
}
~Person()
{
cout << "~Person()" << endl;
}
protected:
string _name;
};
class Student : public Person
{
public:
Student(const char *s = "zhans", int num = 1)
: Person(s)
,
_num(num)
{}
Student(const Student &s)
: Person(s)
,
_num(s._num)
{
}
Student &operator=(Student &s)
{
if (this != &s)
{
_num = s._num;
Person::operator=(s);
}
}
#if 0
~Student()
{
}
#endif
private:
int _num = 1;
};
int main()
{
Student s;
return 0;
}
复杂的菱形继承与
多继承就是一个坑,
单继承:一个类只有一个直接父类
多继承,一个类有多个直接父类 菱形继承是多继承的一种特殊情况,多继承没问题,只不过要避免菱形继承 存在数据冗余和二义性 里面有两份person
先继承前面的,再继承后面的
A一般叫做虚基类 再D里面,A放到一个公共的位置,那么有时候B需要找A,C 需要找A,就需要通过虚基表中的偏移量进行计算
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 = 4;
d._c = 5;
d._d = 6;
return 0;
}
我们尽量不要定义出菱形继承,虚继承
继承的总结和反思
c++的缺陷
- 没有垃圾回收器
- 多继承
继承和组合
class a
{}
class b:public a
{}
class c
{
int_c
}
class d
{
C _obj;
int _d
}
- public继承是一种is_a 的关系,也就是说每个派生类的对象都是一种基类对象,b就是一个a
Student 和Person的关系就适合用继承 ,Student is Person
- 组合是一种has_a的关系,b组合了A,那么就是说b里面有一个a对象
眼睛和头的关系,就适合用组合,头上有眼睛 车和轮胎的关系,车上有轮胎
- 如果它既是is_a 又可以是has_a,那么优先使用has_a(组合)
继承是白箱服用(能看到它的实现细节),组合是黑箱服用(看不见它的实现细节),所以黑盒测试 除了父类的私有成员,其他子类都是可以进行使用的,这样会破坏基类的封装,子类可能会调用父类的公有成员和保护成员,D只能用C 的公有,不能
类和类之间:低耦合,高内聚(跟我没关系的东西,不要设计进来), 类和类之间 的依赖程序低,方便我们维护,所以组合的耦合程度低, 组合下来,保护的成员也是无法使用的
组合关系之间依赖关系小,关联程度低,修改很方便,可维护性强
切割和切片就是继承的好处 而多态就是建立在继承的基础之上,
|