C++继承
来源:互联网 发布:rgb转16进制java 编辑:程序博客网 时间:2024/06/01 07:29
继承的概念:
通过继承机制,可以利用已有的数据来定义新的数据类型。新的数据类型不仅拥有新的成员,同时也拥有旧的成员。我们称已经存在的用来派生新类的类为基类,也称父类。由已存在的的类派生出的新类为派生类,也称子类。是面向对象复用的重要手段。
基类:基类负责定义在各层次关系中所有类的共同成员。
派生类:派生类负责定义各自特有的成员。
class Person //父类/基类{private: int _age; string _name;};class Student/*子类/派生类*/:public/*访问限定符*/ Person {private: int _num;};
继承方式:
1.public 公有继承
基类的公有成员和保护成员作为派生类的成员,保持原有状态和属性,私有成员不能被这个派生类的子类访问。
2.protected 保护继承
基类的所有公有成员和保护成员都成为派生类的保护成员,并且他们只能被派生类成员函数或友元访问,基类的私有成员依然是私有的。
如果一些基类成员不想被基类对象直接访问,但需要在派生类中访问,就应该将其声明为protected成员
3.private 私有继承
基类的公有成员和保护成员都称为派生类的私有成员,并且不能被这个派生类的子类所访问。
4.使用class时,默认继承方式为private,使用struct时,默认继承方式为pbulic。
不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,但是基类的私有成员存在但不可以访问。
下面只对pbulic 继承方式进行演示:
class Date{public: int _day;protected: int _month;private: int _year;};class Day:public Date{public: void Fun(){ _day = 1; //公有成员 _month = 1; //保护成员只能在父类和子类内部使用 _year = 1; //在父类中是私有成员,在子类中无法访问。 }};int main(){ Day d1; d1._day = 10; d1._month = 10; //无法在类外访问 d1._year = 10; //无法访问保护成员 return 0;}
继承与转换:
1.赋值兼容规则:public继承
在需要基类对象的时候,可以使用共有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数,析构函数以外的所有成员,而且所有成员的访问控制属性与基类完全相同。则该公有派生类就具备了基类的所有功能。
(1).派生类的对象可以赋值给基类。
(2).派生类的对象可以初始化基类的引用。
(3).派生类对象的地址可以赋给指向基类的指针/引用。
(4).用公有派生类代替基类。
class Person{public: void Display() { cout << _name << endl; }private: string _name;};class Student:public Person{public: int _num;};void test(){ Person p; Student s; p = s; //子类可以初始化父类 //Person *p1 = &s; //Person &r1 = s;//父类的指针和引用可以指向子类对象}
继承中的构造与析构:
class Person{public: Person(const char *name = "", int id = 0) :_name(name) ,_number(id) {}protected: string _name; //姓名 int _number; //身份证};class Student :public Person{public: Student(const char*name, int id, int stuNum) :Person(name,id) ,_num(stuNum) {} void Display() { cout << "学号" << _num << endl; cout << "身份证" << Person::_number << endl; cout << "姓名" << _name << endl; }protected: int _num; //学号};
该代码的对象模型为
可以看出如果想要构造一个Student类型的对象,需要调用父类的构造函数对子类中的父类成员进行初始化。
同样,在析构一个子类对象时,需要调用父类的析构函数对子类中的父类成员进行析构。
注意:如果父类的构造函数中有参数时,需要在子类的初始化列表中显示调用。(因为编译器无法提供一个默认构造函数)
调用顺序:
派生类的构造函数:父类的构造函数—成员对象的构造函数—子类的构造函数。
析构函数则与构造函数相反。
测试函数:
class Date{public: Date() { cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; }};class Base{public: Base(){ cout << "Base()" << endl; } ~Base() { cout << "Base()" << endl; }};class Derived:public Base{public: Derived(){ cout << "Derived()" << endl; } ~Derived() { cout << "Derived()" << endl; }private: Date d1;};void test() { Derived d2;}int main(){ test(); system("pause"); return 0;}
测试结果:
继承中的重名情况:
1.成员变量重名:
class A{public: int a; int b;};class B :public A{public: int b; int c;};void test() { B b1; b1.b = 10; b1.A::b = 20;}
对象模型为
可以看出里面的有2分相同名字的成员,在进行直接访问b成员时,会直接访问派生类中的b,如果想要访问A中的b,则需要加上作用域。
2.成员函数重名:
成员函数重名与成员变量重名基本相同,在不声明作用域的情况下,默认调用子类中的成员。
class A{public: void DisPlay() { cout << "A" << endl; }};class B :public A{public: void DisPlay() { cout << "B" << endl; }};void test() { B b1; b1.DisPlay(); b1.A::DisPlay();}
单继承与多继承:
单继承:
一个子类只有一个直接父类。
多继承:
一个子类有两个或两个以上的直接父类称为多继承关系。
菱形继承:
对象模型:
class A{public: int _a;};class B1 :public A{public: int _b1;};class B2 :public A{public: int _b2;};class D :public B1, public B2{public: int _d;};void test(){ D d1; d1._a = 1;}
这里会出现D::a,不明确的错误提示。
此时调用出监视窗口会发现
在创建出的d1对象中,_a有两份。所以当你直接访问时,编译器不知道该给哪一个赋值。
所以菱形继承存在二义性问题
对于base class的调用时,要说明作用域。
void test(){ D d1; d1._b1 = 1; d1._b2 = 2; d1._d = 3; d1.B1::_a = 4; d1.B2::_a = 5;}
- c继承
- C++----------------继承
- 【c#】继承
- C++:继承
- C++::继承
- [C++]继承
- 【C++】继承
- 【C#】继承
- 【c++】继承
- 【C++】继承
- c#-继承
- 【C++】 继承
- 【C#】继承
- C++|继承
- 【C++】继承
- C/C++--私有继承
- [C/C++]继承
- c++:私有继承,公有继承,保护继承
- 日常作业2
- 数据库分片(Sharding)与分区(Partition)的区别
- BZOJ[1192]鬼谷子的钱袋 乱搞
- set,map,list小小的总结
- what's the difference between CPU and GPU
- C++继承
- 关与MySql数据库的事物,视图,索引,备份和恢复
- kali安装sogou(google)输入法(附带更新源的操作)
- 网站开发之ie下在线浏览pdf文件无需本地支持
- 心理学和人工智能第一部分 心理学(二)
- 弹性分布式数据集:一种对内存集群计算的容错抽象(三)
- 多线程“锁”要点
- 安装 Kali Linux 后需要做的 20 件事
- O(n)时间求解最佳交易模型