(继承及其访问限定符)(派生类及其默认成员函数)(赋值兼容规则)
◆继承:
★继承概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
继承定义格式
★继承关系&访问限定符
class Base
{
public:
Base()
{
cout<<"B()" <<endl;
}
~Base ()
{
cout<<"~B()" <<endl;
}
void ShowBase()
{
cout<<"_pri = " <<_pri<< endl;
cout<<"_pro = " <<_pro<< endl;
cout<<"_pub = " <<_pub<< endl;
}
private:
int _pri;
protected:
int _pro;
public:
int _pub;
};
class Derived:public Base
{
public:
Derived()
{
cout<<"D()"<<endl;
}
~Derived ()
{
cout<<"~D()"<<endl;
}
void ShowDerived()
{
cout<<"_d_pri = "<<_d_pri<< endl;
cout<<"_d_pro = "<<_d_pro<< endl;
cout<<"_d_pub = "<<_d_pub<< endl;
}
private:
int _d_pri;
protected:
int _d_pro;
public:
int _d_pub;
};
总结:
基类的private成员在派生类中是不能被访问的,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
protetced/private继承是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,是 has-a 的关系原则,所以非特殊情况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。
不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存在但是在子类中不可见(不能访问)。
使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承.
◆派生类的默认成员函数
在继承关系里面,在派生类中如果没有显示定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数。
【继承关系中构造函数调用顺序】
【说明】
1、基类没有缺省构造函数,派生类必须要在初始化列表中显式给出基类名和参数列表。
2、基类没有定义构造函数,则派生类也可以不用定义,全部使用缺省构造函数。
3、基类定义了带有形参表构造函数,派生类就一定定义构造函数。
【继承关系中析构函数调用过程】
class Test1
{
public:
Test1( int data){cout <<"Test1()"<<endl;}
~Test1 (){cout<< "~Test1()"<<endl ;}
};
class Test2
{
public:
Test2( int data){cout <<"Test2()"<<endl;}
~Test2 (){cout<< "~Test2()"<<endl ;}
};
class Base1
{
public:
Base1( int data): _data(data )
{cout <<"Base1()"<<endl;}
~Base1 (){cout<< "~Base1()"<<endl ;}
protected:
int _data;
};
class Base2
{
public:
Base2( int data): _data2(data )
{cout <<"Base2()"<<endl;}
~Base2 (){cout<< "~Base2()"<<endl ;}
protected:
int _data2;
};
class Derive: public Base1, public Base2
{
public:
//Derive(): Base1(0), Base2(1),t1(3), t2(4)
//Derive(): Base2(0), Base1(1),t2(3), t1(4)
//Derive(): t1(3), t2(4), Base1(0), Base2(1)
Derive(): t2 (3), t1 (4), Base2 (0), Base1(1 )
{cout <<"Derive()"<<endl;}
~Derive (){cout<< "~Derive()"<<endl ;}
protected:
Test1 t1;
Test2 t2;
};
继承体系中的作用域
在继承体系中基类和派生类是两个不同作用域。
子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)--隐藏 --重定义
注意在实际中在继承体系里面最好不要定义同名的成员。
class Person
{
public:
Person( const char * name = "" , int id = 0)
: _name(name ), _num( id)
{}
protected:
string _name; // 姓名
int _num; // ×××号
};
class Student: public Person
{
public :
Student(const char * name, int id, int stuNum)
: Person(name , id ), _num(stuNum )
{}
void DisplayNum()
{
cout<<" ×××号: "<<Person :: _num<< endl ;
cout<<" 学号"<< _num << endl ;
}
protected :
int _num ; // 学号
};
★继承与转换--赋值兼容规则--public继承
子类对象可以赋值给父类对象(切割/切片)
父类对象不能赋值给子类对象
父类的指针/引用可以指向子类对象
子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
★友元与继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
class Person
{
friend void Display(Person &p , Student&s);
protected :
string _name ; // 姓名
};
class Student: public Person
{
protected :
int _stuNum ; // 学号
};
void Display(Person &p , Student &s)
{
cout<<p._name<<endl;
cout<<s._name<<endl;
cout<<s._stuNum<<endl;
}
void TestPerson1()
{
Person p;
Student s;
Display (p, s);
}
★继承与静态成员
基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例。
class Person
{
public :
Person(){++ _count;}
protected :
string _name ; // 姓名
public :
static int _count; // 统计人的个数。
};
int Person::_count = 0;
class Student : public Person
{
protected :
int _stuNum ; // 学号
};
class Graduate :public Student
{
protected:
string _seminarCourse; // 研究科目
};
void TestPerson1()
{
Student s1;
Student s2;
Student s3;
Graduate s4;
cout<<"人数:"<<Person::_count<<endl;
Student ::_count = 0;
cout<<"人数:"<<Person::_count<<endl;
}
★单继承&多继承&菱形继承
【单继承】
一个子类只有一个直接父类时称这个继承关系为单继承。
【多继承】
一个子类有两个或以上直接父类时称这个继承关系为多继承
【菱形继承】
class Person
{
public :
string _name ; // 姓名
};
class Student : public Person
{
protected :
int _num ; //学号
};
class Teacher : public Person
{
protected :
int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
string _majorCourse ; // 主修课程
};
void Test ()
{
// 显示指定访问哪个父类的成员
Assistant a ;
a.Student ::_name = "xxx";
a.Teacher ::_name = "yyy";
}
虚继承--解决菱形继承的二义性和数据冗余的问题
虚继承解决了在菱形继承体系里面子类对象包含多份父类对象的数据冗余&浪费空间的问题。
虚继承体系看起来好复杂,在实际应用我们通常不会定义如此复杂的继承体系。一般不到万不得已都不要定义菱形结构的虚继承体系结构,因为使用虚继承解决数据冗余问题也带来了性能上的损耗。
转载于:https://blog.51cto.com/10919090/1763357
(继承及其访问限定符)(派生类及其默认成员函数)(赋值兼容规则)相关推荐
- C++>继承,继承方式及其比较,子类和父类对象指针,派生类的默认成员函数,虚继承,继承与友元,继承与静态成员
继承 继承的概念与定义 概念: 继承是指一个子类(或称为派生类)继承父类(或称为基类)的特征(属性和操作).继承是面向对象程序设计时实现代码复用的重要手段,它允许在原有的类的基础上进行扩展,增加功能, ...
- 【C++从入门到踹门】第三篇:类和对象(中)类的默认成员函数
目录 1.类的默认成员函数 2.构造函数 2.1 构造函数引入 2.2 构造函数概念及特点 3. 析构函数 3.1 析构函数引入 3.2 析构函数的概念 3.3 在哪些情况下会程序会执行析构函数? 3 ...
- C++空类的默认成员函数总结
C++空类的默认成员函数总结 做IT就要做精英,至少4000/月吧? JAVAV工程师权威认证 [上海央邦]学一送一,超值![安博亚威]CCIE考试通过率第一! 定向委培RHCA,通过考试年薪10W ...
- 【JavaSE】封装与继承,访问限定符的总结
文章目录 前言 封装 包的封装 如何创建包 导包 private类的封装 继承 super 子类的构造方法 子类继承父类时的内存分配 访问限定符的总结 前言 终于经历了漫长的前期学习的铺垫,我们终于见 ...
- c++类之“对象包含与成员函数不兼容的类型限定符”与“对象含有与成员 函数 “CarBody::Geta” 不兼容的类型限定符”错误的修改
首先看一段代码 #include<iostream> using namespace std; int car_num=0; struct position {double x, y; } ...
- 类的默认成员函数、赋值运算符重载
目录 1.类的6个默认成员函数 2.1 概念 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5.赋值运算符重载 5.1 运算符重 ...
- c++ 公有继承的赋值兼容规则
赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代.通过公有继承,派生类得到了基类中除构造函数.析构函数之外的所有成员,而且所有成员的访问控制属性也和基类完全相同.这样,公有派生 ...
- 3-1:类与对象入门——类的引入和类的定义以及访问限定符和封装还有对面向对象的理解
文章目录 一:面向对象与面向过程 二:类的引入 三:类的定义 (1)C++类的定义 (2)类的两种定义方式 A:声明和定义全部放在类体中 B:定义和声明分开放 四:类的访问限定符及封装 (1)访问限定 ...
- 第五章节 类的继承(访问修饰符)
一.访问修饰符 1.C#中有五种访问修饰符:public.private.protected.internal和protected internal,其具体说明见下表: 访问修饰符 说明 public ...
- 一文带你入门C++,类与对象、6个默认成员函数、this指针以及static关键字。
C++98关键字:63个 一.命名空间规则(namespace) 1.命名空间可以解决函数.全局变量名重复的问题,包在不同的命名空间里的重复函数,实际就是两个完全无关的函数. 2.命名空间允许续嵌套: ...
最新文章
- 华师大计算机网络中心,华东师范大学 单点登录共享校际资源
- 字符串string类的使用:回文
- python argparse_Python 命令行之旅:初探 argparse
- SpringMVC处理自定义异常,通过读取配置文件把错误信息显示在前台页面
- c语言程序设计实训教材,C语言程序设计实训指导书
- Mvc NuGet 数据迁移
- randomized algorithms 有哪些_毛毯分类有哪些 毛毯的种类
- java udp 服务器方_Java的UDP通信的小程序,UDP服务器
- layui爱准挂更新密码静态WEB页(临时)
- ubuntu 14.04.03 LTS(64bit) 安装PyCharm
- 400+节点的Elasticsearch集群运维
- 变量命名规则_Java变量与常量
- Java 用接口实现加减乘除计算器
- Waydev 客户的GitHub 和 GitLab OAuth 令牌被盗,源代码遭访问
- Docker教程小白实操入门(11)--如何构建私有Registry
- .NET中各种数据库连接大全
- macpro的IDEA常用快捷键~持续更新
- java如何把汉字转换成机内码_如何用java随机生成一个汉字?
- Spring之Introductions(简介)应用
- MALTAB中 imshow函数出错
热门文章
- 沈阳python需求大吗_学习Python之后都能做什么,沈阳Python薪资多少钱
- c++ 定时器_「正点原子Linux连载」第十九章定时器按键消抖实验
- 牛客网面试题总结(试券)
- 输出表格csv_自动提取生成excel表格!推荐一款开源工具
- OFFICE技术讲座:标点压缩是各大OFFICE软件差异关键,总体考量有哪些
- 编码基本功:以文件大小进行性能测试是错误的
- 软件基本功:出错了就问别人,大哥你是不是开发人员?
- 炒菜多放油:确实好吃,可是又不健康
- C向Python传递数组参数时,调用函数后才能销毁
- 错误解决办法:_ZNSaIcED1Ev@@GLIBCXX_3.4