栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

面向对象程序设计笔记 继承与派生

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

面向对象程序设计笔记 继承与派生

继承

继承是使代码可以复用的重要手段,也是面向对象程序设计的核心思想之一。简单的说,继承是指一个对象直接使用另一对象的属性和方法。

C++ 中的继承关系就好比现实生活中的父子关系,继承一笔财产比白手起家要容易得多,原始类称为基类,继承类称为派生类,基类是对派生类的抽象,派生类是对基类的具体化。它们是类似于父亲和儿子的关系,所以也分别叫父类和子类。而子类又可以当成父类,被另外的类继承。

派生类的声明方式

声明派生类的一般格式为:
class 派生类名:继承方式 基类名{
派生类新增加的成员
};
继承方式包括:public,protected,private,继承方式是可选的,如果不写继承方式,默认的是private

样例1

 给出文件

#ifndef PEO_H_
#define PEO_H_

#include
#include
using namespace std;

class People{
	public:
		string Name;
		void PrintName();
};

void People::PrintName(){
    cout << "姓名:" << Name << endl;
}
#endif
#include "usr.h"

int main(){
	int id; 
	string name;
	cin >> id >> name ;
    Student st;
    Set(id,name,&st);
    st.PrintSID();
	st.PrintName();
}

要求实现文件        实现如下:

#include "people.h"
#include 
#include 

using namespace std;
class Student:public People{
    private:
        int SID;  
	public:
		void PrintSID();
        friend void Set(int sid,string name,Student *ptr); 
};
void Student::PrintSID(){
    cout << "学号:" << SID << endl;
}

void Set(int sid,string name,Student *ptr){
    ptr->SID=sid;
    ptr->Name=name;
}
保护继承

保护继承相对于公有继承,访问性有所降低,父类的公有成员在子类中变成了保护成员,也就无法在外部通过一个对象访问父类成员了,但是对于这个子类的子类仍然是可见的(因为可见性只是降到了 protected )。

如果要保护继承一个类,只需继承时在类名前面加上 protected 关键字即可。

样例1

  给出文件

#ifndef PEO_H_
#define PEO_H_

#include
#include
using namespace std;
class People{
	public:
		string Name;
		void PrintName();
};

void People::PrintName(){
    cout << "姓名:" << Name << endl;
}

#endif
#include "usr.h"

int main(){
	int id; 
	string name;
	cin >> id >> name ;
    Student st;
    Set(id,name,&st);
    st.PrintSID();
	((People*)&st)->PrintName();
}

要求实现文件        实现如下:

注意到main()中Set()为正常函数(不是成员函数),并且需要访问protected类型的People,所以这里声明为类外的友元函数

#include "people.h"     
#include 
#include 
using namespace std;

class Student:protected People{
	public:
		int SID;
		void PrintSID();
    	friend void Set(int sid,string name,Student* ptr);	
};

void Student::PrintSID(){
    cout << "学号:" << SID << endl;
}

void Set(int sid,string name,Student* ptr){
    ptr->SID=sid;
    ptr->Name=name;
}
重载、重定义(隐藏、覆盖)、重写

重载

产生原因:主要是因为在C++中,编译器在编译.cpp文件中当前作用域的同名函数时,函数生成的符号由返回值类型(不起决定作用)+形参类型和顺序(起决定作用)的组成。

作用:用同一个函数名命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。

重定义

重定义也叫隐藏,指的是在继承关系中,子类实现了一个和父类名字一样的函数,(只关注函数名,和参数与返回值无关)这样的话子类的函数就把父类的同名函数隐藏了。

下面给出一个易错的例子:

class A{
    public:
        int _x;
        void f(){ cout << "A" << endl; }
};

class B:public A{    
    public:
        void f(int a){ cout << "B" << endl; }
};

void test(){
    B b;
    b.f();
}

 上述例子会报错,因为B中的f()覆盖了父类A的f(),所以函数定义是f(int a);

重写

重写指的在继承关系中,子类中定义了一个与父类极其相似的虚函数。
具体怎么相似:函数名必须相同,参数列表必须相同,返回值可以不相同,但是必须是父子关系的指针或引用。

通过重写,可以实现动态多态,何为动态多态,就是当父类的指针或引用指向被重写的虚函数时,父类的指针或引用指向谁就调用谁的虚函数,而不是说根据类型。
在这里,如果去掉父类的虚函数的virtual,则构不成多态,如果去掉子类虚函数的virtual可以构成多态,可以理解为编译器优化。

样例

给出文件

#ifndef PEO_H_
#define PEO_H_

#include
#include
using namespace std;
class People{
	public:
		string Name;
		void PrintName();
};

void People::PrintName(){
    cout << "姓名:" << Name << endl;
}

#endif
#include "usr.h"
int main(){
	int i,j;
	string name;
	cin >> i >> j >> name;
    Graduate st;
    Set(name,i,j,&st);
    ((Student*)&st)->PrintSID();
	((People*)&st)->PrintName();
    st.PrintResearchID();
}

要求实现文件        实现如下:

注意到Student与Graduate中均有Set(),当方法名相同时,子类的函数会覆盖父类的函数(尽管他们的传参列表不相同)(但是可以通过作用域限制来访问Student::Set())(覆盖),

class Student:private People{
	public:
		int SID;
		void PrintSID(){ cout<<"学号:"<Set(string name,int sid);//调用的是Graduate中的成员函数
    ptr->ResearchID=rid;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/889958.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号