c++继承中的构造与析构-派生类获取基类的特性-派生类对基类成员的访问权限

1、explicit 关键字
用于修饰单参数的构造函数,防止编译做隐式转换
class Date
{
public:
explicit Date(int y=2000, int m=1, int d=1): year(y), month(m), day(d){}
private:
int year;
int month;
int day;
};

int main()
{
Date d1(2019, 12, 13);
Date d2;

// 此时,编译器做隐式转换: Date d3 = Date(10);即编译器会用右边的这个值构造一个与左边的对象类型相同的对象,再创建新对象
// 如果构造函数加上explicit ,这种写法就会出错!
Date d3 = 10;
return 0;
}


2、继承
封装:
1、防止用户无意间破坏对象的状态
2、接口与实现的分离
继承:
可以用来定义相似类型并对其关系建模
代码重用、减少代码冗余,提高开发效率


在实现世界中,有很多类型(概念)非常相似,只有细微的差别
如,交通工具、车、船、飞机
如,学生、小学生、中学生、大学生、研究生
....

在C++中,用继承来描述这些相似又不完全相同的类型
通过继承关系联系在一起的类构成一种层次关系,层次关系的根部有一个基类,其它的类或直接或间接的从基类继承而来
这些继承得到类称为派生类
基类负责定义在层次关系中所有类共同拥有的特征(属性、行为)
派生类自动获取基类的特征,并负责定义各自特有的成员


语法格式:
class 派生类名: [继承方式] 基类名1 [, [继承方式] 基类名2, ...., [继承方式] 基类名n]
{
// 派生特有的属性和行为
};

继承方式: 指定了 基类的成员 在其派生类内部 和 派生类外部 的访问权限!
class 的默认继承方式为private
struct 的默认继承方式为public

public 公有继承
private 私有继承(默认)
protected 保护继承

公有继承(掌握)
基类的公有成员,通过公有继承,成为派生类自己的公有成员
基类的私有成员,通过公有继承,成为派生类的一部分,但是不可直接访问
基类的保护成员,通过公有继承,成员为派生类自己的保护成员


私有继承(熟悉即可)
基类的公有成员,通过私有继承,成为派生类自己的私有成员
基类的私有成员,通过私有继承,成为派生类的一部分,但是不可直接访问
基类的保护成员,通过私有继承,成员为派生类自己的私有成员


保护继承(熟悉即可)
基类的公有成员,通过保护继承,成为派生类自己的保护成员
基类的私有成员,通过保护继承,成为派生类的一部分,但是不可直接访问
基类的保护成员,通过保护继承,成员为派生类自己的保护成员


保护成员:
类的内部(成员函数)可访问,友元可访问,派生类可访问,类的外部(通过对象)不可直接访问

 

3、继承中的构造与析构
基类的构造函数与析构函数 不能 被继承。
如果派生类希望传递参数初始化从基类继承来的成员,只能通过成员初始化列表把参数传递给基类的构造函数,以初始化基类的成员
如果基类的成员占用了资源,需要释放,派生类的析构函数会自动调用基类的析构函数!

格式:
派生类构造函数(参数列表):基类的构造函数(参数), ...
{}


创建派生类对象时,先调用基类的构造函数,再调用成员对象的构造函数,最后再调用派生类的构造函数
销毁对象时,先调用派生类的析构函数,再调用成员对象的析构函数,最后再调用基类的析构函数。

如果有多个成员对象,按它们的声明顺序依次构造。


4、函数隐藏
在派生类中,定义与基类的成员函数同名的成员函数
当用派生类对象调用重新定义的同名函数时,只会调用派生类的版本,基类的同名函数自动被隐藏!
如果需要调用被隐藏的基类函数,指定作用域即可:
基类名::被隐藏的函数名(参数);

 

5、is-a关系
基类与它的公有派生类之间存在is-a的关系,即派生类(对象)是一个基类(对象)!
例:
小学生(派生类) 是 学生(基类)
大学生 是 学生

卡车(派生类) 是 车(基类)
小气车 是 车

具体表现:
派生类对象可以用来初始化基类对象
派生类对象可以给基类对象赋值
派生类对象可以用来初始化基类引用
基类指针可以指向派生类对象

总之,任何需要基类的地方,都可以用它的公有派生类来替代。

用派生类初始化的基类对象/指针/引用,无法访问派生类新增加的成员,只能访问派生类继承来的成员!
// 基类(父类/超类)
class Base
{
public:
void foo()
{
cout << "hello Base class" << endl;
}
private:
int a;
protected:
char c;
};

// 派生类(子类)
class Derived: public Base
{
public:
void foo() // 隐藏基类的同名函数
{
Base::foo(); // 调用隐藏的基类函数
cout << "hello Derived class" << endl;
}
void bar()
{
cout << "hello Derived::bar" << endl;
}

};

Derived d1;
Base b1 = d1;
b1.foo(); // 调用的也不是派生类的版本,而是继承来的那个版本
b1.bar(); // error

类似于:
double d = 3.14;
int a = d; // a只有d的整数部分,d的小数部分丢弃不要

 ---------------------

个人学习笔记

posted on 2021-08-27 10:57  kk鼠标  阅读(244)  评论(0)    收藏  举报

导航