目录
4.友元的概述
在C++程序中,有些私有属性也想让类外特殊的一些函数或者类进行访问,那么就需要友元的技术。
友元的目的就是让一个函数或者类访问另外一个类中的私有成员。
友元的关键字为 friend。
4.1 全局函数做友元
先创建一个房子类,客厅作为公共成员(Public),卧室作为私有成员(Private)。如下:
4.2 类做友元
通常情况下,类之间的私有属性是不可以访问的,但是声明某个类为本类的友元类的之后就可以访问本类中的私有属性了。如下:
4.3 成员函数做友元
//告诉编译器,GoodGay类下的visit成员函数作为本类的好朋友可以访问本类中的私有属性
friend void GoodGay::visit();如此就可以使某个类中的成员函数访问到本类中的私有成员。
5.C++中运算符的重载
运算符重载的概念:
对已有的运算符重新进行定义,赋予另外一种功能,以适应不同的数据类型(主要是针对自定义的一些数据类型的运算,如Person,Phone等自定义的类型的数据。对于内置的数据类型的运算符的定义时无法改变的。),面对非内置的数据类型的运算,计算机不会进行自动运算而报错,所以需要我们重新定义某个运算符,赋予我们想要实现的功能。如:若直接将Peson类型中的per1和per2两个对象的age相加,per3 = per1 + per2,计算机将无从下手而报错。
如下:
5.1 加号运算符重载
5.1.1 利用成员函数重载加号
//编译器起的通用名称 operator+
Person operator+(Person& per)
{
Person temp;//创建一个临时对象
temp.m_age = this->m_age + per.m_age;//将 当前调用该函数的对象的m_age 与 传入的 per的m_age 赋值给新的对象temp
temp.m_wight = this->m_wight + per.m_wight;
}本质调用:Person per3 = per1.operator+(per2) ;
简化为: per3=per1+per2;
5.1.2 通过全局函数重载加号
本质调用:Person per3.operator(per1, per2);
简化:per3 = per1 + per2 ;
对加号进行重载后相加运行后的结果如下:
5.1.3 运算符重载也可以发生函数重载
Person operator+(Person& per, int num) { };
本质调用,如:Person per2.( per1 , 10);
简化为:Person per2 = per1 + 10 ;
5.2 左移运算符重载
作用:可以输出自定义的类型。
5.3 递增运算符重载
5.4 赋值运算符重载
5.5 关系运算符重载
5.6 函数调用运算符重载
6.继承的概述
1. 概念:继承是指在一个现有类的寄出上构建一个新的类,构建的新类称为子类,现有类称为父类,子类会自动继承父类的属性和方法,使得子类具有父类的特征和行为。
2.继承的好处:减少重复代码。
6.1 继承的基本语法
1. 先创建一个父类,里面的属性为众多子类的公共属性。
2. 创建子类。继承父类属性时的格式为: class 子类 :继承方式 父类 { };
如,class Java : public BasePage{ };
子类除了可以继承福诶的属性和方法,也可以定义自己的属性和方法。
3. 子类 也称为 派生类 ; 父类 也称为 基类
#include<iostream>
using namespace std;
//继承实现页面
//1. 先建立一个父类
class BasePage
{
public:
//1.1 提取出所有公共属性:
void header()
{
cout << "首页,公开课,登录,注册...(公共头部)" << endl;
}
void footer()
{
cout << "帮助中心,交流合作,站内地图...(公共底部)" << endl;
}
void left()
{
cout << "Java,C++,Python,...(公共分类列表)" << endl;
}
};
// 2. 建立子类继承父类的属性,并根据自身来定义自己的属性和方法
//这里的各个子类不同的属性和方法就是 方法content()的输出内容
//Java 页面
class Java : public BasePage
{
public:
void content()
{
cout<< "java学科视频" << endl;
}
};
//Python页面
class Python : public BasePage
{
public:
void content()
{
cout << "python学科视频" << endl;
}
};
//C++页面
class CPP : public BasePage
{
public:
void content()
{
cout << "c++学科视频" << endl;
}
};
//测试方法
void test1()
{
cout << "Java下载视频的页面如下:" << endl;
Java ja;
ja.header();
ja.footer();
ja.left();
ja.content();
cout << "---------------------------" << endl;
cout << "python下载视频的页面如下:" << endl;
Python py;
py.header();
py.footer();
py.left();
py.content();
cout << "----------------------------" << endl;
cout << "C++下载视频的页面如下:" << endl;
CPP cpp;
cpp.header();
cpp.footer();
cpp.left();
cpp.content();
}
int main()
{
test1();
system("pause");
return 0;
}
6.2 继承的方式
继承语法: class 子类 : 继承方式 父类
继承方式:
公共继承 public ;
保护继承 protect ;
私有继承 private ;
6.3 继承中的对象模型
1. 在父类中所有的非静态成员属性都会被子类继承下去,只是父类中的私有成员属性被编译器隐藏掉了,因此是访问不到的,但是确实是被继承下来了,只是不可访问而已。
2. 通过VS的开发人员命令提示符 工具打印 对象模型,来查看对象模型。
步骤:
1. 跳转盘符 如 E:
2. 跳转文件路径 cd 具体路径。
3. 查看命令格式:
cl /d1 reportSingleClassLayout类名 文件名 (按下 Tab 键可以自动补齐)
( cl 中的 ‘ l ’ 是小写英文字母 ‘ l ’ ,d1 中的 ‘ 1 ’ 是数字 ‘ 1 ’ )
6.4 构造和析构顺序
子类继承父类之后,当创建子类对象时,也会调用父类的构造函数。
那么,父类和子类的构造和析构顺序谁先谁后呢?
创建一个父类Base和一个子类用于测试如下:
程序在调用对象的时候会自动调用构造和析构函数,而且只会调用一次,所以我们只要创建一个对象就可以调用两个函数了。
1. 创建一个父类对象,测试结果如下图一,正常调用。
2.创建一个子类对象,测试结果如下图三。可以发现父类与子类的构造和析构函数调用的顺序:先构造父类,再构造子类 ;先析构子类,再析构父类。
6.5 同名成员处理
问题1:当子类与父类出现同名的成员时,如何通过子类对象访问到子类或者父类中的同名成员的数据呢?
1. 若是子类对象访问子类中的同名成员,则直接访问即可。如,son.m_age ;
2. 若是子类对象访问父类中的同名成员,则需要加作用域。如, son. Base :: m_age;
3. 当子类中没有某成员而父类中有时,直接访问调用的就是父类中的成员 ;若子类中含有,则直接访问调用的就是 子类中的成员。
问题2:如果父类和子类中存在同名成员函数的同时,父类中还有一个同名的重载函数,那么子类对象能不能直接访问这个重载函数呢? 怎样可以访问到呢?如果是子类中含有这样一个同名的重载函数又是怎样的结果呢?
如果子类中出现父类同名的函数,子类的同名成员函数会隐藏掉父类中所有同名的成员函数。所以直接访问是错误的,想要访问父类中被隐藏的同名成员函数,需要加作用域。
即:子类对象,加作用域可以访问父类中的同名成员函数
6.6 同名静态成员处理
问题:继承中同名的静态成员在子类对象上如何进行访问?
静态成员与非静态成员出现同名,处理方式一致。
访问子类同名成员,直接访问即可。
访问父类同名成员,需要加作用域。
不同的是,非静态同名成员只能用对象访问,静态成员除了能用对象来访问,还可以直接用类名进行访问,那么如何通过子访问父类中的同名静态成员呢?
具体如下所示:
1. 同名静态成员属性:
2.同名静态成员函数:
6.7 多继承语法
1. 概念:C++允许一个类继承多个类。
2. 语法: class 子类 : 继承方式 父类1 ,继承方式 父类2 ....
注意:多继承可能引发父类中有同名成员出现,需要加作用域区分。在C++实际开发过程中不建议使用多继承。
6.8 菱形继承问题以及解决办法
1. 菱形继承概念:两个派生类继承同一个基类,又有某个类同时继承着两个派生类,这种继承称为菱形继承,或者钻石继承。
2. 需要利用 虚继承 来解决菱形继承的问题,vbptr(虚基类指针 v - virtual ; b - Base ; ptr - pointer): 指向一个 vbtable (虚基类表)。
7.多态的概述
1. 多态分为两类:
静态多态:函数重载 和 运算符重载 属于静态多态,复用函数名。
多态多态:派生类和虚函数实现运行时多态。
2. 静态多态和动态多态的区别:
静态多态的函数地址早绑定:编译阶段确定函数地址。
动态多态的函数地址晚绑定:运行阶段确定函数地址。
3. 动态多态满足条件:
1. 有继承关系
2. 子类重写父类的虚函数重写:函数返回类型 函数名 参数列表 完全一致 称为 重写。
4. 动态多态的使用:
父类的指针或者引用 指向子类对象