目录
一,为什么需要继承
二,继承的基本概念
三,派生类的定义
四,继承中的析构预构造
1,子类中的构造与析构的顺序
2,子类调用成员对象,父类的有参构造
五,子类与父类的同名处理
1.子类和父类 同名成员数据
2.子类和父类 同名成员函数
一,为什么需要继承
目的:提高代码重用,提高i开发效率。例如我们已经拥有了制作某一零件的整套设备,以这套设别为基础之上,通过改造这个设备以实现其他种零件的制作,省去了从新研发等的时间。类比于c++语言中,就是通过实现继承该类并改造,实现其他功能。
二,继承的基本概念
c++最重要的特征是代码重用,通过继承机制可以利用已有的数据类型来定义新的数据类型,新的类不 仅拥有旧类的成员,还拥有新定义的成员。 一个B类继承于A类,或称从类A派生类B。这样的话,类A成 为基类(父类), 类B成为派生类(子类)。
派生类中的成员,包含两大部分: 一类是从基类继承过来 的,一类是自己增加的成员。 从基类继承过过来的表现其共性,而新增的成员体现了其个性。
如图所示:
例如给定一个基类,我们可理解为是一个父亲类,在继承父亲类的某些功能,定义的新类也就是派生类(这里可当作子类),子类除了继承以外的功能,还有自己的一些功能。
三,派生类的定义
我们通常这样定义子类(派生类),在有基类的前提下,定义子类在类定义的基本方式下,还需在后添加:继承方式 基类名
class 父类{};
class 子类:继承方式 父类名
{
//新增子类数据
};
这里的继承方式就是所谓基类中的public,private ,protected中的类型的成员,一般这里我们是使用公共继承的。
如图以下的三种继承方式:
继承方式决定他们可以继承过来成员在派生类中是什么类型的,故我们可以知道,任何父类都不能将私有类型数据通过继承给予子类。如下:
#include<iostream>
using namespace std;
//定义基类
class Base
{
private:
int a;
protected:
int b;
public:
int c;
};
//定义派生类
class Son :public Base
{
public:
void fun()
{
cout << b << c << endl;
//cout<<a<<endl;不可访问
}
};
int main()
{
Son a;
// cout <<a.b<< endl;//不可访问
cout << a.c<< endl;
a.fun();
return 0;
}
很显然如果是公有继承过来,b还是保护型的,对于私有的直接是无法继承,所以这里的b是无法访问的。
四,继承中的析构预构造
1,子类中的构造与析构的顺序
对于派生类中的构造与析构的顺序看可用下图展示:
即构造时:先构造父类,再构造对象中的构造函数,最后才是子类的构造,而析构就是与之相反。
如下:
class Base
{
public:
Base()
{
cout << "父类构造" << endl;
}
~Base()
{
cout << "父类析构" << endl;
}
};
class member
{
public:
member()
{
cout << "对象构造" << endl;
}
~member()
{
cout << "对象析构" << endl;
}
};
class Son :public Base
{
public:
member a;
Son()
{
cout << "子类构造" << endl;
}
~Son()
{
cout << "子类析构" << endl;
}
};
int main()
{
Son p;
return 0;
}
我们可以看到构造与析构的顺序。
2,子类调用成员对象,父类的有参构造
子类实例化对象时会自动调用成员对象、父类的默认构造。
子类实例对象时必须使用初始化列表 调用成员对象、父类的有参构造。(无参构造就不需要)
初始化列表时:父类写类名称 成员对象用对象名。
class Base
{
public:
Base()
{
cout << "父类构造" << endl;
}
Base(int a)
{
cout << "父类有参构造" << endl;
x = a;
}
~Base()
{
cout << "父类析构" << endl;
}
int x;
};
class member
{
public:
member()
{
cout << "对象构造" << endl;
}
member(int a)
{
cout << "对象有参构造" << endl;
y = a;
}
~member()
{
cout << "对象析构" << endl;
}
int y;
};
class Son :public Base
{
public:
member a;
int c;
Son()
{
cout << "子类构造" << endl;
}
Son(int a, int b, int c) :Base(a), a(b)//初始化列表,基类用基类名显式调用,而对象调用用对象名么人不是类名
{
this->c = c;
cout << "Son有参构造" << endl;
}
~Son()
{
cout << "子类析构" << endl;
}
};
int main()
{
Son p(10,20,30);
return 0;
}
注意初始化列表中基类与成员的构造调用!!
五,子类与父类的同名处理
我们先给出最实用的方法:
同名成员最简单最安全的处理方式:加作用域
1.子类和父类 同名成员数据
子类默认优先访问子类的同名成员
必须加父作用域 访问父类的同名成员。
class Base
{
public:
int a;
public:
Base(int a)
{
this->a = a;
}
};
class son :public Base
{
public:
int a;
son(int x, int y) :Base(x)
{
a = y;
}
};
//这里同名,但优先是子类成员
int main()
{
son a(10, 20);
cout << a.a <<endl;//20
//给a加上作用域
cout << a.Base::a << endl;//10
}
2.子类和父类 同名成员函数
class Base
{
public:
void fun()
{
cout << "调用基类中fun" << endl;
}
int a;
};
class son :public Base
{
public:
void fun()
{
cout << "调用派生类中fun" << endl;
}
};
//这里同名,但优先是子类成员
int main()
{
son a;
a.fun();
a.Base::fun();
return 0;
}