C++面向对象程序设计-北京大学-郭炜【课程笔记(七)】

C++面向对象程序设计-北京大学-郭炜【课程笔记(七)】

  • 1、类型转换运算符
  • 2、自增、自减运算符的重载
  • 3、继承和派生的基本概念
    • 3.1、基本概念
    • 3.2、派生类对象的内存空间
  • 4、继承关系和复合关系
    • 4.1、继承关系的使用
    • 4.2、复合关系的使用
  • 5、派生类覆盖基类成员
  • 6、存储权限说明符:protected
  • 7、派生类的构造函数
  • 8、public继承的赋值兼容规则
  • 9、直接基类与间接基类(套娃)

毕业中:学习速度较慢
开始课程:P21 6_6. 类型转换运算符的重载
课程链接:程序设计与算法(三)C++面向对象程序设计 北京大学 郭炜
课程PPT:github提供的对应课程PPT

1、类型转换运算符

重载强制类型转换符 double 形式:operator double () {return real};
类型转换符重载是不需要写返回值类型的,默认其double自身。

案例:解释包含在代码中

#include <iostream>
using namespace std;

class Complex
{
    double real, imag;
    public:
        Complex(double r=0, double i=0):real(r), imag(i) {};
        operator double () {return real;}
        // 重载强制类型转换运算符 double,返回类型就是double,不用单独写出
};

int main()
{
    Complex c(1.2, 3.4);
    cout << (double)c << endl;   // 输出1.2  //等价于c.operator double()
    double n = 2 + c;  // 等价于double n = 2+c.operator double()
	// 本来2和c是不能相加的,因为2为一个整形数字,c确实一个对象,
	// 所以这里调用了重载类型转换运算符
    cout << n; // 输出 3.2
}

2、自增、自减运算符的重载

  • 自增运算符++、自检运算符–有前置/后置之分,为了区分所有重载的是前置运算符还是后置运算符,C++规定:

  • 前置运算符作为一元运算符重载

  • 重载为成员函数:
    T & operator++();
    T & operator–();
    重载为全局函数:
    T & operator++(T &);
    T & operator—(T &);
    使用样例:++obj, obj.operator++(), operator++(obj) 都调用上述函数

  • 后置运算符作为二元运算符重载,多写一个没用的参数即可,这参数不具备任何意义,也不会被使用;

  • 重载为成员函数:
    T operator++(int);
    T operator–(int);
    重载为全局函数:
    T operator++(T &, int);
    T operator–(T &, int);
    使用样例:obj++, obj.operator++(0), operator++(obj,0) 都调用上函数

注意事项:在vs中,obj++也调用前置重载,而dev则令obj++编译出错。

案例:课程中的所有解释均在代码中呈现,请配合课程看代码;

#include<iostream>
using namespace std;

class CDemo
{
    private:
        int n;
    public:
        CDemo(int i=0):n(i) {}
        CDemo & operator++();   // 用于前置形式,返回值为引用
        CDemo operator++(int);  // 用于后置形式,返回值为对象
        // 后置类型的++为什么没使用&引用呢!
        // 答:在C++中 ++a;a的返回值就是a的引用;所以在重载前置++运算符时,我们需要尽量维持它原本的属性。   

        operator int() {return n;}  // 类型强制转换运算符,直接可以cout输出对象

        friend CDemo & operator--(CDemo &);     // 全局前置
        friend CDemo operator--(CDemo &, int);  // 全局后置
};

CDemo & CDemo::operator++()  // 返回值为CDemo对象的引用
{
    // 前置 ++
    ++n;
    return * this;   // 返回值是一个对象,即对* this的引用;
}  // ++s即为:s.operator++(),即返回值就是s的引用(& s)

CDemo CDemo::operator++(int k)  // 这里的k是无用的参数; 返回值为CDemo对象
{
    // 后置 ++
    CDemo tmp(*this);   // 记录修改前的对象
    n++;
    return tmp;         // 返回修改前的对象
}  // s++即为:s.operator(0);

CDemo & operator--(CDemo & d)  // 这里的引用可不是只为了节省空间,而是要通过该引用更改成员变量
{
    // 前置--
    d.n--;
    return d;   // 返回对操作数的引用,即d的引用
}  // --s即为:operator--(s)

CDemo operator--(CDemo & d, int)
{
    // 后置--
    CDemo tmp(d);  // 生成一个临时的对象,因为后置本身输出的值大小不变,但其运行完后,该对象中的--或++才生效,所以返回的对象是其自身。
    d.n--;
    return tmp; // 返回操作数的对象,即d
}  // s--即为:operator--(s, 0)

int main()
{
    CDemo d(5);
    cout << (d++) << ","; //等价于 d.operator++(0);   //重载为成员函数的形式
    cout << d << ",";   // 可以重载左移运算符或者重载一个强制类型转换运算符即可输出d;
    cout << (++d) << ","; //等价于 d.operator++();    //重载为成员函数的形式
    cout << d << endl;
    cout << (d--) << ","; //等价于 operator--(d,0);   //重载为全局函数的形式
    cout << d << ",";
    cout << (--d) << ","; //等价于 operator--(d);     //重载为全局函数的形式
    cout << d << endl;
    return 0;
}

// OUT
MacBook-Air beida_lesson % g++ 21.cpp -o 21
MacBook-Air beida_lesson % ./21
5,6,7,7
7,6,5,5

注意事项:一共有以下一些观点:

由上述代码可知,后置运算符的重载比前置运算符的重载多了一个临时函数的构建,所以前置运算符在时间上的开销要小于后置运算符重载的开销,特别是遇到递归时,变得就比较明显了。所以提倡写前置运算符。

请添加图片描述

3、继承和派生的基本概念

3.1、基本概念

  • 继承:在定义一个新的类B时,如果该类与某个已有的类A相似(指的是B拥有A的全部特点),那么就可以把A作为一个基类,而把B作为基类的一个派生类(也称子类)
  • 派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量和成员函数。
  • 派生类一经定义后,可以独立使用,不依赖于基类。
  • 派生类拥有基类的全部成员函数和成员变量,不论是private、protected、public。
    • 在派生类的各个成员函数中,不能访问基类中的private成员。

案例

  • 所有学生都有的共同属性:
    • 姓名
    • 学号
    • 性别
    • 成绩
  • 所有学生都有的共同方法:(成员函数)
    • 是否该留级
    • 是否该奖励
  • 不同学生又有个字==各自不同的属性和方法
    • 研究生
      • 导师
    • 大学生
    • 中学生
      • 竞赛特长加分
class CStudent
{
	private:
		string sName;
		int nAge;
	public:
		bool IsThreeGood() {};
		void SetName(const string & name)
		{
			sName = name;
		}
};

// 要毕业的学生
class CUndergraduateStudent: public Cstudent
{
	private:
		int nDepartment;  // 添加自己的新的成员变量
	public:
		bool IsThreeGood() {.....};  // 覆盖(与基类的成员函数名一样,但内容不一样)
		bool CanBao Yan() {.....};
};   // 派生类的写法是:类名:public基类名

// 研究生
class CGraduatedStudent:public CStudent
{
	private:
		int nDepartment;
		char szMentorName[20];
	public:
		int CountSalary() {.....};
}

3.2、派生类对象的内存空间

派生类对象的体积,等于基类对象的体积,再加上派生类对象自己的成员变量的体积。在派生类对象中,包含着基类对象,而且基类对象的春初位置位于派生类对象新增的成员变量之前
在这里插入图片描述

举例一个完整的例子:两个类的简单学生管理程序

// File name:22.cpp
#include<iostream>
#include<string>
using namespace std;

class CStudent
{
    private:
        string name;
        string id;  // 学号
        char gender; // 性别, “F”代表女, “M”代表男
        int age;
    public:
        void PrintInfo();
        void SetInfo(const string & name_, const string & id_, int age_, char gender_);
        string GetName() {return name;}
};

void CStudent::PrintInfo()
{
    cout << "Name = " << name << endl;
    cout << "ID = " << id << endl;
    cout << "Age = " << age << endl;
    cout << "Gender = " << gender << endl;
}

void CStudent::SetInfo(const string & name_, const string & id_,
            int age_, char gender_)
{
    name = name_;
    id = id_;
    age = age_;
    gender = gender_;
}

class CUndergraduateStudent:public CStudent
{
    // 本科生类,继承了CStudent类
    private:
        string department;  // 学生所属的系的名称
    public:
        void QualifiedForBaoyan()
        {
            // 输出给予保研资格
            cout << "qualified for baoyan" << endl;
        }
        void Printfo()   // 覆盖:CUndergraduateStudent自己的Printfo
        {
            CStudent::PrintInfo();   // 调用基类PrintInfo
            cout << "Department:" << department << endl;
        }
        void SetInfo(const string & name_, const string & id_, 
                    int age_, char gender_, const string & department_)
        {
            CStudent::SetInfo(name_, id_, age_, gender_);  // 调用基类的Setinfo
            department = department_;
        }
};

int main()
{
    CUndergraduateStudent s2;
    s2.SetInfo("Harry Potter", "118829212", 19, 'M', "Computer Science");
    cout << s2.GetName() << "" ;
    s2.QualifiedForBaoyan();
    s2.PrintInfo();
    return 0;
}

// OUT
MacBook-Air beida_lesson % g++ 22.cpp -o 22
MacBook-Air beida_lesson % ./22
Harry Potterqualified for baoyan
Name = Harry Potter
ID = 118829212
Age = 19
Gender = M

4、继承关系和复合关系

继承关系:“是” 关系

  • 基类A,B是基类A的派生类。
  • 逻辑上要求:“一个B对象也是一个A对象”。(例:从学生类派生出中学生类,因为中学生也是学生。)

复合关系:“有”关系。

  • 类C中“有”成员变量k,k是类D的对象,则C和D是复合关系
  • 一般逻辑上要求:“D对象是C对象的固有属性或组成部分”。

4.1、继承关系的使用

在这里插入图片描述
请添加图片描述

4.2、复合关系的使用

请添加图片描述在这里插入图片描述在这里插入图片描述

5、派生类覆盖基类成员

派生类可以定义一个和基类成员同名的成员,这叫覆盖。在派生类中访问这类成员时,缺省的情况是访问派生类中定义的成员。要在派生类中访问有基类定义的同名成员时,要使用作用域符号::


class base
{
    int j;
    public:
        int i;
        void func();
};

class derived : public base
{
    public:
        int i;
        void access();
        void func();
};

void derived::access()
{
    // j = 5; // error,这是base的私有成员变量,派生类derived不能访问
    i = 5; // 引用的是派生类的i
    base::i = 5; // 引用的基类的i
    func();  // 派生类的
    base::func(); // 基类的

}

int main()
{
    derived obj;
    obj.i = 1;   // 派生类的i
    obj.base::i = 1;  // 引用的基类的i
}

// 在派生类和基类中不要写相同的成员变量,如上代码中的i

注意事项:在派生类和基类中不要写相同的成员变量,如上代码中的i

6、存储权限说明符:protected

在这里插入图片描述
特点:基类的protected成员:可以被以下函数访问:

  • 基类的成员函数
  • 基类的有缘函数
  • 派生类的成员函数可以访问当前对象的基类的保护成员
class People
{
    private: int nPrivate;  // 私有成员
    public: int nPublic;    // 公有成员
    protected: int nProtected;  // 保护成员
};

class Son:public People
{
    void Accesspeople()
    {
        nPublic = 1;     // Ok
        nPrivate = 1;    // wrong
        nProtected = 1;  // Ok, 访问从基类继承的protected成员
        Son f;  // 非当前对象 
        f.nProtected = 1; // wrong, f 不是当前对象
    }
};

int main()
{
    People f; 
    Son s;
    f.nPublic = 1;
    s.nPublic = 1;
    f.nProtected = 1; 
    f.nPrivate = 1; 
    s.nProtected =1; 
    s.nPrivate = 1; 
}

7、派生类的构造函数

在这里插入图片描述


class Bug
{
    private:
        int nLegs;
        int nColor;
    public:
        int nType;
        Bug(int nLegs_, int nColor_);
        void PrintBug(){};
};

class FlyBug:public Bug  // FlyBug是Bug的派生类
{
    int nWings;
    public:
        FlyBug(int nLegs_, int nColor_, int nWings_);
};

Bug::Bug(int legs, int color)
{
    nLegs = legs;
    nColor = color;
}

// 错误的FlyBug构造函数
FlyBug::FlyBug(int legs, int color, int wings)
{
    nLegs = legs;   // 不能访问
    nColor = color; // 不能访问
    nType = 1;      // OK,基类的公有成员,没有问题的
    nWings = wings;
}

// 正确的FlyBug构造函数
// 直接初始化派生类所包含的基类的Bug对象(即Bug构造函数)初始化列表
FlyBug::FlyBug(int legs, int color, int wings):Bug(legs, color) // 基类的构造函数
{
    nWings = wings;
}

int main()
{
    FlyBug fb(2, 3, 4);  // 调用构造函数初始化
    fb.PrintBug();
    fb.nType = 1;
    fb.nLegs = 2;   // error , nLegs is private
    return 0; 
}

在这里插入图片描述
例:

#include <iostream>

class Base
{
    public:
        int n;
        Base(int i):n(i)
        {std::cout << "Base" << n << " constructed " << std::endl;}
        ~Base()
        {std::cout << "Base " << n << "destructed" << std::endl;}
};

class Derived:public Base
{
    public:
        Derived(int i):Base(i) // 1、先进入Base构造函数
        { std::cout << "Derived constructed " << std::endl;} //2、进入Drivate构造函数
        ~Derived()
        {std::cout << "Derived destructed" << std::endl;}
};

int main()
{
    Derived Obj(3);
    return 0;
    // 3、执行 Derived析构函数
    // 4、执行 Base析构函数
}

// OUT
MacBook-Air beida_lesson % ./23
Base3 constructed 
Derived constructed 
Derived destructed
Base 3destructed

例题2:

#include <iostream>

class Bug
{
    private:
        int nLefs; int nColor;
    public:
        int nType;
        Bug(int legs, int color);
        void PrintBug() {};
};

class Skill
{
    public:
        Skill(int n) {};
};

class nWings
{
    public:
        nWings(int nWings_) {};
};

class FlyBug:public Bug
{
    nWings w1;
    Skill sk1, sk2;

    public:
        FlyBug(int legs, int color, int wings);
};

FlyBug::FlyBug(int legs, int color, int wings):
    Bug(legs, color), sk1(5), sk2(2), w1(wings) {}

老师版本:

#include <iostream>

class Bug
{
    private:
        int nLefs; int nColor;
    public:
        int nType;
        Bug(int legs, int color);
        void PrintBug() {};
};

class Skill
{
    public:
        Skill(int n) {};
};

class FlyBug:public Bug
{
    int nWings;
    Skill sk1, sk2;

    public:
        FlyBug(int legs, int color, int wings);
        // nWings(int nWings_) { nWings = nWings_};
};

FlyBug::FlyBug(int legs, int color, int wings):
    Bug(legs, color), sk1(5), sk2(2), nWings(wings) {}

请添加图片描述
请添加图片描述

8、public继承的赋值兼容规则

以下等号“=”并没有采用运算符重载。

请添加图片描述

9、直接基类与间接基类(套娃)

请添加图片描述
请添加图片描述
例:

#include <iostream>

class Base
{
    public:
        int n;
        Base(int i):n(i)
        {std::cout << "Base" << n << " constructed " << std::endl;}
        ~Base()
        {std::cout << "Base " << n << "destructed" << std::endl;}
};

class Derived:public Base
{
    public:
        Derived(int i):Base(i)
        { std::cout << "Derived constructed " << std::endl;}
        ~Derived()
        {std::cout << "Derived destructed" << std::endl;}
};

class MoreDerived:public Derived
{
    public:
        MoreDerived():Derived(4)
        {
            std::cout << "More Derived constructed" << std::endl;
        }
        ~MoreDerived()
        {
            std::cout << "More Derived destructed " << std::endl;
        }
};

int main()
{
    MoreDerived Obj;
    return 0;
}

// OUT
    ~MoreDerived()
    ^
2 errors generated.
MacBook-Air beida_lesson % g++ 23.cpp -o 23
MacBook-Air beida_lesson % ./23            
Base4 constructed 
Derived constructed 
More Derived construct

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/557378.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NFT Insider #127:STEPN与阿迪达斯合作推出独家NFT运动鞋

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members &#xff08;https://twitter.com/WHALEMembers&#xff09;、BeepCrypto &#xff08;https://twitter.com/beep_crypto&#xff09;联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜…

C# 字面量null对于引用类型变量✓和值类型变量×

编译器让相同的字符串字面量共享堆中的同一内存位置以节约内存。 在C#中&#xff0c;字面量&#xff08;literal&#xff09;是指直接表示固定值的符号&#xff0c;比如数字、字符串或者布尔值。而关键字&#xff08;keyword&#xff09;则是由编程语言定义的具有特殊含义的标…

阿里云服务器怎么更换暴露的IP

很多客户阿里云服务器被攻击IP暴露&#xff0c;又不想迁移数据换服务器&#xff0c;其实阿里云服务器可以更换IP&#xff0c;今天就来和大家说说流程&#xff0c;云服务器创建成功后6小时内可以免费更换公网IP地址三次&#xff0c;超过6小时候就只能通过换绑弹性公网IP的方式来…

第二部分 Python提高—GUI图形用户界面编程(六)

其他组件学习 文章目录 OptionMenu 选择项Scale 移动滑块颜色选择框文件对话框简单输入对话框通用消息框ttk 子模块控件 OptionMenu 选择项 OptionMenu(选择项)用来做多选一&#xff0c;选中的项在顶部显示。显示效果如下&#xff1a; from tkinter import * root Tk();ro…

栈和队列OJ(面试高频题 - 看完包!!!拿捏)

目录 题目一&#xff1a;括号匹配问题&#xff08;来源&#xff09; 题目描述 题目思路及实现 题目二&#xff1a;用队列实现栈&#xff08;来源&#xff09; 题目描述 题目思路及实现 题目三&#xff1a;用栈实现队列&#xff08;来源&#xff09; 题目描述 题目思路及实现 …

C# 窗体应用程序 Chart控件显示实时曲线

IDE: VS2019 项目模板&#xff1a;C# windows 窗体应用(.NET Framework) 【参考】 B站上教程C#Chart控件画折线图的使用&#xff0c;关于Chart控件的属性&#xff0c;介绍得非常详细。B站上教程C#上位机Chart控件实时曲线终极讲解&#xff0c;对鼠标滚轮事件等&#xff0c;多…

数据结构初阶-二叉树

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 二叉树 树概念和结构 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限节点组成的一个具有层次关系的集合&#xff0c;把它叫做树…

在H5开发App应用程序过程中的一些常见问题

哈喽&#xff0c;大家好呀&#xff0c;淼淼又来和大家见面啦&#xff0c;H5开发是一种可以跨平台、跨设备、且可以在各种设备上运行&#xff0c;无需安装额外的应用程序。最近有许多小伙伴跟我聊到在h5开发App应用程序的过程中遇到了一些问题&#xff0c;今天我们就这些问题来做…

赫克Hurco触摸屏维修工控机显示屏G190EG01

美国赫克Hurco工控机控制器维修C5SH11 Hurco工控机电脑维修 主要适用范围是&#xff1a;石油和石油化学工业、灶矿、油田、化学工业、化纤工业、油漆工业、肥料工业、各种制造工业。石油轮和车辆、飞机、仓库、电解车间、通讯机装配车间、要求工具不生锈、抗磁的场所等。 hurc…

SQL连接查询

连接查询&#xff1a; 同时涉及多个表的查询称为连接查询。 SQL中连接查询的主要类型 (1) 交叉连接&#xff08;广义笛卡尔积&#xff09; (2) 等值连接 (3) 自身连接 (4) 内连接 (5) 外连接 1.交叉连接 使用笛卡尔积运算的连接方式 笛卡尔积运算&#xff1a;设A&#xff…

Java 的注释

文章目录 java 的注释共有三种形式单行注释多行注释文档注释文档注释的文档需要命令进行生成GBK 不可映射问题 与大多数的编程语言一样&#xff0c;Java 中的注释也不会出现在可执行程序中。 因此我们可以在源程序中根据需要添加任意多的注释&#xff0c;而不必担心可执行代码受…

LeetCode:203.移除链表元素

&#x1f3dd;1.问题描述&#xff1a; &#x1f3dd;2.实现代码&#xff1a; typedef struct ListNode ListNode; struct ListNode* removeElements(struct ListNode* head, int val) {if(headNULL)return head;ListNode *NewHead,*NewTail;ListNode *pcurhead;NewHeadNewTail…

揭秘七星创客模式:如何轻松实现财富增长

亲爱的朋友们&#xff0c;我是微三云的周丽&#xff0c;一名专注于私域电商模式创新的探索者。 在当今商业社会&#xff0c;随着科技的飞速发展和互联网的普及&#xff0c;商业模式的创新和变革成为企业发展的关键。其中&#xff0c;七星创客模式以其独特的魅力和gao效的yun营…

这就是酷雷曼500位合作商成功的底气

你只管赚钱&#xff0c;其它交给总部&#xff01; 敢做出这样的承诺&#xff0c;酷雷曼凭的就是“保姆式”的帮扶政策。酷雷曼致力于建立一个可持续良效发展的合作商运营体系&#xff0c;无论是落地扶持还是培训服务&#xff0c;全方位为合作商保驾护航&#xff01; 陪跑式落…

注意力机制基本思想(一)

​&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客&#x1f525; 系列专栏&#xff1a; &#x1f3c0;《深度学习基础知识》 相关专栏&#xff1a; ⚽《机器学习基础知识》 &#x1f3d0;《机器学习项目实战》 &#x1f94e;《深度学习项目实战…

超详细Web程序设计基础知识,新手设计师快收藏!

Web 程序设计是现代计算机科学的核心领域之一。它涉及到开发各种不同类型的网站和应用程序&#xff0c;从基本的静态页面到复杂的动态应用程序。本文将介绍 Web 程序设计的基础知识&#xff0c;包括 JavaScript、HTML、CSS 等方面的内容。 1、JavaScript JavaScript 是一种脚…

【Web】Dest0g3 520迎新赛 题解(全)

目录 phpdest EasyPHP SimpleRCE funny_upload EasySSTI middle PharPOP ezip NodeSoEasy Really Easy SQL&easysql EzSerial ljctr phpdest 尝试打pearcmd&#xff0c;但似乎没有写文件的权限 ?config-create/&file/usr/local/lib/php/pearcmd.php&a…

C++学习————第七天(初始化列表、static,友元,内部类)

今天已经是C学习第七天&#xff0c;希望这篇文章能够给大家带来更多的帮助&#xff0c;相应文章都放在C学习专栏里面。 C学习————第五天&#xff08;构造函数 析构函数 拷贝构造函数&#xff09;-CSDN博客 C学习————第六天 &#xff08;运算符重载 const成员 取地址&…

[渗透测试学习] Monitored-HackTheBox

Monitored-HackTheBox 信息搜集 nmap扫描一下端口 nmap -sV -sC -v --min-rate 1000 10.10.11.248扫描结果如下 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0) 80/tcp open http Apache httpd …

阿里巴巴拍立淘API让购物更智能:图片搜索商品,信息快速呈现,个性化推荐更精准

随着互联网的不断发展&#xff0c;电子商务已经成为人们日常生活中不可或缺的一部分。然而&#xff0c;传统的文本搜索方式在购物过程中往往存在信息不匹配、效率低下等问题。为了解决这些问题&#xff0c;阿里巴巴推出了拍立淘API&#xff0c;通过图片搜索商品的方式&#xff…