您的位置:首页 > 新闻 > 资讯 > 重庆电子工程职业学院招生信息网_智能小程序入口_重庆seo代理_chatgpt网址

重庆电子工程职业学院招生信息网_智能小程序入口_重庆seo代理_chatgpt网址

2024/10/9 7:13:22 来源:https://blog.csdn.net/in_seattle/article/details/142638011  浏览:    关键词:重庆电子工程职业学院招生信息网_智能小程序入口_重庆seo代理_chatgpt网址
重庆电子工程职业学院招生信息网_智能小程序入口_重庆seo代理_chatgpt网址

🌈个人主页:羽晨同学 

💫个人格言:“成为自己未来的主人~”  

 继承的概念和定义

继承是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行拓展,增加功能,这样可以产生新的类,叫做派生类,继承呈现了面向对象的程序设计的层次结构,继承是类设计层次的复用

class Person
{
public:Person(){}void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;cout<<_tel<<endl;}string _name = "peter";//姓名
protected:int _age = 18;//父类定义本质,不想被子类继承
private:int _tel = 110;
};
//继承的父类的成员
class Student :public Person
{
public:void Func(){//子类用不了(不可见)//cout << _tel << endl;cout << _name << endl;cout << _age << endl;}
protected:int _stuid;//学号
};
class Teacher :public Person
{
protected:int _jobid;//工号
};

在这个代码当中,我们简单的使用继承创建了两个对象。

 所以,我们看到的是Person是父类,也被叫做基类,Student是子类,也称作派生类。


继承管理和访问限定符 

继承基类成员访问方式的变化。

 

在这其中,如果我们使用public继承和类成员是public成员或者protected成员,是可以直接使用成员,其他的就不可以,例如:

class Student :public Person
{
public:void Func(){//子类用不了(不可见)cout << _tel << endl;cout << _name << endl;cout << _age << endl;}
protected:int _stuid;//学号
};

在这里,我们的_tel在Person中时private修饰的,所以派生类中不能进行调用。

但是,父类的私有成员变量是可以父类的成员函数来间接调用的,例如:

class Person
{
public:Person(){}void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;cout<<_tel<<endl;}string _name = "peter";//姓名
protected:int _age = 18;//父类定义本质,不想被子类继承
private:int _tel = 110;
};

在实际使用中一般使用的都是public继承,几乎很少使用protected/private继承 

派生类和基类对象的赋值转换

我们假如让p=s,这个是可以实现的,但这个实现的逻辑并不是类型转换,而是一种特殊的语法规则,不会产生任何的中间变量,我们可以看下面的代码实现逻辑。

int main()
{Student s;Person p;//跟下面机制不一样//特殊语法规则:不是类型转换,中间没有产生临时变量p = s;Person* ptr = &s;Person& ref = s;ptr->_name += 'x';ref._name += 'y';s._name += 'z';return 0;
}

  • 基类对象不能赋值给派生类对象。
  • 派生类对象可以赋值给基类的对象/基类的指针/基类的引用,这里我们可以叫做切片或者切割。

那类型转换下的情况是什么吗?

这个就是我们经常说到的,截断和提升。 

继承中的作用域

基类和派生类都有独立的作用域

子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫做隐藏,也叫做重定义(在子类成员函数中,可以使用基类:基类成员显示访问)

如果是成员函数之间的隐藏,只要函数名相同就能构成隐藏。

在实际中,最好不要在继承体系里面定义同名的成员

#include<iostream>
using namespace std;
//student的_num和Prson的_num构成隐藏关系,可以看出代码虽然可以运行,但是非常容易混淆
class Person
{
protected:string _name = "小李子";int _num = 111;
};
class Student :public Person
{
public:void Print(){cout << "姓名" << _name << endl;cout << "学号" << _num << endl;//隐藏,重定义cout << "学号" << Person::_num << endl;}
protected:int _num = 999;
};
int main()
{Person p;Student s;s.Print();return 0;
}

你看,这里面就涉及到了隐藏和重定义。

 派生类的默认成员函数

6个默认成员函数

  • 初始化和清理
  1. 构造函数主要完成初始化工作
  2. 析构函数主要完成清理工作
  • 拷贝复制
  1. 拷贝构造是使用同类对象初始化创建对象
  2. 赋值重载主要是把一个对象赋值给另一个对象
  • 取地址重载
  1. 主要是普通函数和const对象取地址,这两个很少会自己实现

 在子类中,父类的那部分调用父类的什么函数,这个就叫做复用。

构造:

构造的时候,我们要先父后子,因为子类中关于父类成员的部分会用到父类的构造,

析构:

析构的时候,我们要先子后父,因为子类的析构可能会用到父类的析构函数。

class Person
{
public:Person(const char* name = ""):_name(name){cout << "Person()" << endl;}Person(const Person& p):_name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person& operator=(const Person& p)" << endl;if (this != &p){_name = p._name;}return *this;}~Person(){cout << "~Person()" << endl;delete[] _str;}
protected:string _name;char* _str = new char[10] {'x', 'y', 'z'};
};
class Student :public Person
{
public://父类构造显示调用,可以保证先父后子Student(const char*name="",int x=0,const char*address=""):_x(x),_address(address),_name(Person::_name+'x'),Person(name){}Student(const Student&st):Person(st),_x(st._x),_address(st._address){}Student& operator=(const Student& st){if (this != &st){Person::operator=(st);_x = st._x;_address = st._address;}return *this;}//由于多态,析构函数的名字会被统一处理成destructor()//父类析构不能显示调用,因为显示调用不能保证先子后父~Student(){//析构函数会构成隐藏,所以这里要指定类域cout << "Student()" << endl;cout << _str << endl;}
protected:int _x = 1;string _address = "sdasa";string _name;
};

好了,本次的文章就到这里了,我们下次再见。 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com