用路由器建设网站,网站查询备案信息,网站标题大全,标识导视设计公司官网学过c的人都知道#xff0c;c的三大特性#xff1a;封装、继承、多态。
我们今天说的是c的继承#xff0c;那么为什么要引入继承#xff0c;它有什么特点呢#xff1f;
首先#xff0c;继承的特点是#xff1a;使代码复用#xff0c;为后面学习多态做铺垫。
继承分为…学过c的人都知道c的三大特性封装、继承、多态。
我们今天说的是c的继承那么为什么要引入继承它有什么特点呢
首先继承的特点是使代码复用为后面学习多态做铺垫。
继承分为私有继承private、公有继承public、保护继承protected。
分别举例介绍一下它们各自的特性吧
一、继承
私有继承
//Inherit.h #pragma once
#includeiostream
using namespace std;class Base
{
public:Base(){}void FunTest(){cout_priendl;}int _pub;
protected:int _pro;
private:int _pri;
};class Derived:private Base //私有继承基类Base
{
public:Derived(){}void Function(){cout_pubendl;}
private:int _d;
};//Inherit.cpp #includeInherit.hint main()
{Base b;Derived d;d._pri 10; //errord._pro 20; //errord._pub 30; //errord.Function();return 0;
} 通常我们把继承自基类的类称为派生类。
运行结果 由上述结果可知对于私有继承下的派生类来说在基类中的公有成员及成员函数继承到派生类就变为私有基类的保护也变为派生的私有基类的私有则不继承下去。当然私有继承下的派生类中的成员及成员函数不能在类外被访问。
保护继承
//Inherit.h #pragma once
#includeiostream
using namespace std;class Base
{
public:Base(){}void FunTest(){cout_priendl;}int _pub;
protected:int _pro;
private:int _pri;
};class Derived:protected Base
{
public:Derived(){}void Function(){cout_pubendl;}
private:int _d;
};class Third:protected Derived
{
public:void F(){cout_pubendl;}
private:int _third;
};//Inherit.cpp #includeInherit.hint main()
{Base b;Derived d;Third t;d._pri 10; //errord._pro 20; //errord._pub 30; //errord.Function();t.F();return 0;
}运行结果 由上述结果可知对于保护继承下的派生类来说在基类的公有成员及成员函数继承到派生类中就变为私有基类的保护也变为派生的保护基类的私有则不继承下去。此时如果变为保护则在有继承关系的类与类之间可以互相访问而在类外不可访问。
公有继承
//Inherit.h #pragma once
#includeiostream
using namespace std;class Base
{
public:Base(){}void FunTest(){cout_priendl;}int _pub;
protected:int _pro;
private:int _pri;
};class Derived:public Base
{
public:Derived(){}void Function(){cout_pubendl;}
private:int _d;
};class Third:protected Derived
{
public:void F(){cout_pubendl;cout_proendl;}
private:int _third;
};//Inherit.cpp #includeInherit.hint main()
{Base b;Derived d;Third t;d._pri 10; //errord._pro 20; //errord._pub 30;d.Function();t.F();return 0;
}
运行结果 由上述结果可知对于公有继承下的派生类来说在基类的公有成员及成员函数继承到派生类中仍为公有即在类外也可访问基类的保护也变为派生的保护基类的私有则不继承下去。
下面拿一个表格来总结一下吧~ 注若类中省略以何种方式继承时默认为私有继承。
二、调用顺序
例1
//Inherit.h #pragma once
#includeiostream
using namespace std;
class Base
{
public:Base(){coutBase()endl;}~Base(){cout~Base()endl;}
private:int _b;
};class Derived:public Base
{
public:Derived(){coutDerived()endl;}~Derived(){cout~Derived()endl;}
private:int _d;
};//Inherit.cpp #includeInherit.h
int main()
{Base b;Derived d;getchar();return 0;
}运行结果 调用顺序分析
Base b;创建一个基类的对象b则调用基类的构造函数Derived d;创建一个派生类对象d则调用派生类的构造函数此时这里没有直接的调用派生类的构造函数而是调用基类的构造函数最后再调用派生类的构造函数。(在派生类对象调用构造函数时是在派生类对象构造函数的初始化列表中调用了基类的构造函数)
如派生类构造函数原型为 Derived():Base(){coutDerived()endl;}
例2 //Inherit.h #pragma once
#includeiostream
using namespace std;class Base
{
public:Base(){coutBase()endl;}~Base(){cout~Base()endl;}
private:int _b;
};class C
{
public:C(){coutC()endl;}~C(){cout~C()endl;}
};
class Derived:public Base
{
public:Derived():Base(){coutDerived()endl;}~Derived(){cout~Derived()endl;}
private:C _c;
};//Inherit.cpp #includeInherit.h
int main()
{Base b;Derived d;getchar();return 0;
}运行结果 构造函数的调用次序
初始化列表的构造函数--成员变量的构造函数--派生类的构造函数
三、继承体系的作用域
要知道继承体系中基类和派生类是在两个不同的作用域中。
类中有很多函数那么当基类的成员函数和派生类的成员函数同名了怎么办呢它会调用哪个函数呢
例
//Inherit.h #pragma once
#includeiostream
using namespace std;
class Base
{
public:Base(){}void Fun(){coutBase::Fun()endl;}
protected:int _b;
};class Derived
{
public:Derived(){}void Fun(){coutDerived::Fun()endl;}
private:int _d;
};//Inherit.cpp #includeInherit.h
int main()
{Base b;Derived d;d.Fun();system(pause);return 0;
}运行结果 当用派生类的对象调用与基类同名的函数的时候派生类会调用自己的成员函数。把基类的函数隐藏起来。这被称作同名隐藏。只要函数名相同就会出现同名隐藏
四、赋值兼容规则
关于赋值大家再熟悉不过了吧。有同一类型的赋值有不同类型的赋值可能会用到强制类型转换哦。
这里我们要掌握的是基类与派生类之间的赋值
例
1、派生类对象赋给基类对象切割、切片
2、基类对象不能赋给派生类对象
3、基类的指针或引用指向派生类对象
4、派生类的指针或引用不能指向基类的对象。可以通过强制类型转换完成
例
//Inherit.h #pragma once
#includeiostream
using namespace std;
class A
{
public:A(){coutA()endl;}int _a;
};class B:public A
{
public:B(){coutB()endl;}int _b;
};//Inherit.cpp#includeInherit.h
int main()
{A a;B b;a b;b a; //error,无法将基类对象赋给派生类对象A *pA NULL;B *pB NULL;pA pB;pB pA; //error无法让派生类指针给span stylefont-family: Arial, Helvetica, sans-serif;基/spanspan stylefont-family: Arial, Helvetica, sans-serif;类指针/span
A aa b;B bb a; //error,无法让派生类的引用给基类对象return 0;
}上述错误的赋值和指向可以通过强制类型转化。改 五、几种不能继承的关系
1、友元关系不能继承。
2、对于静态成员及静态成员函数则整个继承体系中只有一个这样的成员。无论派生出多少个子类都只有一个这样的static成员实例。
例1
//Inherit.h #pragma once
#includeiostream
using namespace std;
#includestring
class Person
{friend void Display(Person p,Student s);
public:string p_name;
};
class Student:public Person
{
public:string s_no;
};void Display(Person p,Student s)
{coutp.p_nameendl;couts.p_nameendl;couts.s_noendl;
}//Inherit.cpp#includeInherit.h
int main()
{Person p;Student s;Display(p,s); //error,无法识别Studentreturn 0;
}这里说明的就是友元关系不能继承。
例2
//Inherit.h #pragma once
#includeiostream
using namespace std;
#includestring
class Person
{
public:Person(){coutPerson()endl;_count;}
protected:string _name;
public:static int _count;
};int Person::_count 0;class Student:public Person
{
protected:int _num;
};class Graduate:public Student
{
protected:string _course;
};//Inherit.cpp#includeInherit.h
int main()
{Student s;Graduate g;coutPerson::_countendl;coutStudent::_countendl;Student::_count 0;coutStudent::_countendl;coutPerson::_countendl;return 0;
}运行结果注友元函数和static成员函数都没有this指针。
六、单继承多继承
上述讲述的都是单继承的形式那么多继承是什么样子的呢
例 class A
{
public:A(){}
protected:int _a;
};class B
{
public:B(){}
protected:int _b;
};class C:public A ,public B //实现多继承c既可以访问A类的公有和保护成员也可以访问B类的公有和保护成员。
{
public:C(){}
protected:int _c;
} 七、菱形继承也称钻石继承
形如 代码如下
Inherit.h #pragma once
#includeiostream
using namespace std;
class B
{
public:B(){}
protected:int _b;
};
class C1:public B
{
public:C1(){}
protected:int _c1;
};class C2:public B
{
public:C2(){}
protected:int _c2;
};class D:public C1,public C2
{
public:D(){}
private:int _d;
}; Inherit.cpp #includeInherit.h
int main()
{B b;C1 c1;C2 c2;D d;coutsizeof(B)endl; //打印类B中成员所以它的size为4coutsizeof(C1)endl; //打印类C1中的成员并且继承了类B所以它的size为8coutsizeof(C2)endl; //打印类C2中的成员并且继承了类B所以它的size为8coutsizeof(D)endl; //打印类D的成员并且继承了类C1C2所以它的size为20return 0;
}运行结果 内存中是这样的形式出现的 八、虚继承
为了解决菱形继承的二义性问题又引出了虚继承的概念。在内存中添加了一个地址用来存放偏移量。虽然浪费了空间但是解决了二义性问题。
就如上述菱形继承一样通常我们在用D d创建一个对象之后用派生类的对象调用基类的成员时不知道到底是C1还是C2继承下来的成员这时就会出现二义性。为了解决上述问题的二义性我们引出了虚继承。
例
Inherit.h class B
{
public:B(){}
protected:int _b;
};class C1:virtual public B
{
public:C1(){}
protected:int _c1;
};class C2:virtual public B
{
public:C2(){}
protected:int _c2;
};class D:public C1,public C2
{
public:D(){}
private:int _d;
}; Inherit.cpp int main()
{B b;C1 c1;C2 c2;D d;coutsizeof(B)endl; //只有一个成员所以size为4coutsizeof(C1)endl; //类C1自己的成员和继承自B的成员还有一个存放偏移量的虚地址size为12coutsizeof(C2)endl; //类C2自己的成员和继承自B的成员还有一个存放偏移量的虚地址size为12coutsizeof(D)endl; //继承自C1C2所以size为24return 0;
}运行结果 形式如图所示 继承的内容就先说到这里啦讲的不详细的还希望大家能给出建议哦。
欢迎大家来访~~