C++学习笔记 (二)面向对象:封装、继承、多态

1.内存

分四区(意义:对不同区域的数据,赋予不同的生命周期,给我们更大的灵活编程)

(1)代码区:存放二进制代码,由操作系统管理

(2)全局区:存放全局变量、静态变量、常量(该区数据由系统释放)

(3)堆区:由人分配、释放。若人没手动释放,则结束时会由操作系统回收(用new在堆区开辟内存,用delete释放)

 

new返回的是该类型数据的指针,如int* p = new int(10);

C++学习笔记 (二)面向对象:封装、继承、多态_第1张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第2张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第3张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第4张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第5张图片

 

 

C++学习笔记 (二)面向对象:封装、继承、多态_第6张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第7张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第8张图片

(4)栈区:由编译器自动分配、释放,存放函数参数、局部变量等

C++学习笔记 (二)面向对象:封装、继承、多态_第9张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第10张图片

 

2.引用

作用:用来给变量起别名

数据类型 &别名 = 原名;

C++学习笔记 (二)面向对象:封装、继承、多态_第11张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第12张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第13张图片

 

(1)用引用,必须要初始化,且之后就不能更改了

C++学习笔记 (二)面向对象:封装、继承、多态_第14张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第15张图片

以上输出的a、b、c都是20 。

C++学习笔记 (二)面向对象:封装、继承、多态_第16张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第17张图片

 

(2)引用做函数参数

作用:函数传参时,可以用引用的技术让形参修饰实参

优势:与地址传递的效果一样,其更好理解。

C++学习笔记 (二)面向对象:封装、继承、多态_第18张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第19张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第20张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第21张图片

 

(3)引用做函数的返回值

C++学习笔记 (二)面向对象:封装、继承、多态_第22张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第23张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第24张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第25张图片

 

(4)引用的本质是指针常量(指针的指向不可改,指向的值可改)

C++学习笔记 (二)面向对象:封装、继承、多态_第26张图片

 

(5)常量引用

C++学习笔记 (二)面向对象:封装、继承、多态_第27张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第28张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第29张图片

 

3.函数

(1)默认参数

C++学习笔记 (二)面向对象:封装、继承、多态_第30张图片

 

(2)占位参数

C++学习笔记 (二)面向对象:封装、继承、多态_第31张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第32张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第33张图片

 

(3)函数重载

作用:函数名可以相同,提高复用性

需满足3个条件:

①同一个作用域   

②函数名称相同       

③参数类型不同或个数不同或顺序不同

(函数返回值不能作为函数重载的条件)

C++学习笔记 (二)面向对象:封装、继承、多态_第34张图片

函数重载注意事项:

C++学习笔记 (二)面向对象:封装、继承、多态_第35张图片

 

4.类和对象

面向对象的3大特性:封装、继承、多态

c++认为万事万物皆为对象,有属性与行为。

二者关系:把具有相同性质的对象,可以抽象称之为类

C++学习笔记 (二)面向对象:封装、继承、多态_第36张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第37张图片

(1)封装的意义:类在设计时,可以把属性和行为放在不同的权限下,加以控制

访问权限有3种:

public 公共权限,成员类内外都可访问;

protected 保护权限,成员类内可访问(同一个class内),类外不行,儿子(如A:public B)可以访问父亲中的保护内容

private 私有权限,成员类内可访问,类外不行,儿子不能访问父亲中的保护内容;

C++学习笔记 (二)面向对象:封装、继承、多态_第38张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第39张图片

注:

C++ 访问权限问题主要包括两种:一种是外界(类外)对类成员的普通访问,通过类内的public;另一种是继承关系中子类对父类成员的访问。

基本原则:外界只能访问类中public成员,子类可访问父类的public和protected成员;不同继承方式只影响外界(包括子类的子类)通过子类对父类成员的访问权限。

一、 外界对类成员的普通访问

1. 当类成员在类中为public权限时,才可在类外访问,其余不可。

2. 若存在继承关系,从父类继承来的成员若在该类中仍具有public权限,也可在类外访问,其余不可。
二、继承关系中子类对父类成员的访问

1. 无论通过什么方式(public、protected、private)继承,在子类内部均可访问父类中的public、protected成员,private成员不可访问。

    注意:

      继承方式只影响外界(包括子类的子类)通过子类对父类成员的访问权限。

      public继承,父类成员的访问权限全部保留至子类;

      protected继承,父类public成员的访问权限在子类中降至protected;

      private继承,父类public、protected成员的访问权限在子类中均降至private。

2. 父类的析构函数若声明为protected (无论有无virutal),外界均不可调用delete 父类指针;因为是protected权限,子类析构后会自动调用父类析构函数。

   这种情况下,最好不要在父类成员中有动态内存分配。

3. 通过protected/private继承的子类,不能通过static_cast/dynamic_cast向父类转换;只能通过reinterpret_cast引用或指针的方式强制转换,按照父类内存结构重新解释,可改变成员的访问权限。

举例

C++学习笔记 (二)面向对象:封装、继承、多态_第40张图片

可见以上目前存在私有的访问权限问题,解决方法有两种:

①  改为成员函数,父类的成员函数是可以访问自己的私有成员的

C++学习笔记 (二)面向对象:封装、继承、多态_第41张图片

②  改为友元函数,可以在类外访问私有变量

C++学习笔记 (二)面向对象:封装、继承、多态_第42张图片

 

(2)同样表示的是类,struct与class唯一的区别在于默认的访问权限不同:struct默认公有,class默认私有

C++学习笔记 (二)面向对象:封装、继承、多态_第43张图片

 

(3)成员属性设置为私有的好处:可以自己控制读写权限。且对于写权限,我们可以检测数据的有效性。

         再通过类内设置的get()、set()方法来读取或改写私有属性

C++学习笔记 (二)面向对象:封装、继承、多态_第44张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第45张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第46张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第47张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第48张图片

#include 
using namespace std;

//创建立方体类
//设计属性
//设计行为 获取立方体面积和体积
//分别利用全局函数和成员函数 判断两个立方体是否相同
class Cube
{
    int m_L;
    int m_W;
    int m_H;
public:
    void setL(int l) //设置长
    {
        m_L = l;
    }
    int getL() //获取长
    {
        return m_L;
    }

    void setW(int w)
    {
        m_W = w;
    }
    int getW()
    {
        return m_W;
    }

    void setH(int h)
    {
        m_H = h;
    }
    int getH()
    {
        return m_H;
    }

    int calculateS()
    {
        return 2*(m_L*m_W + m_L*m_H + m_W*m_H);
    }

    int calculateV()
    {
        return m_L*m_W*m_H;
    }

    //用成员函数判断两个立方体是否相同
    bool isSameByClass(Cube &c)
    {
        if(m_L==c.getL() && m_W==c.getW() && m_H==c.getH())
            return true;
        return false;
    }

};

bool isSame(Cube &c1, Cube &c2);

int main()
{
    Cube c1;
    c1.setL(10);
    c1.setW(10);
    c1.setH(10);
    cout << "c1面积: " << c1.calculateS() << endl;
    cout << "c1体积: " << c1.calculateV() << endl;

    Cube c2;
    c2.setL(10);
    c2.setW(10);
    c2.setH(11);

    if(isSame(c1, c2))
        cout << "全局函数判断: c1和c2相同 \n";
    else
        cout << "全局函数判断: c1和c2不同 \n";

    if(c1.isSameByClass(c2))
        cout << "成员函数判断: c1和c2相同 \n";
    else
        cout << "成员函数判断: c1和c2不同 \n";

    return 0;
}

//用全局函数判断两个立方体是否相同
bool isSame(Cube &c1, Cube &c2)
{
    if(c1.getL()==c2.getL() && c1.getW()==c2.getW() && c1.getH()==c2.getH())
        return true;
    return false;
}

C++学习笔记 (二)面向对象:封装、继承、多态_第49张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第50张图片

#include 
using namespace std;

//点类
class Point
{
    int m_X;
    int m_Y;
public:
    void setX(int x)
    {
        m_X = x;
    }
    int getX()
    {
        return m_X;
    }

    void setY(int y)
    {
        m_Y = y;
    }
    int getY()
    {
        return m_Y;
    }
};

class Circle
{
    int m_R;
    Point m_Center;
public:
    void setR(int r)
    {
        m_R = r;
    }
    int getR()
    {
        return m_R;
    }

    void setCenter(Point center)
    {
        m_Center = center;
    }
    Point getCenter()
    {
        return m_Center;
    }
};

//判断点与圆的关系
void isInCircle(Circle &c, Point &p)
{
    //c.getCenter()返回的m_Center是Point类,所以可以直接调用Point的getX()、getY()方法。
    int Distance =
            (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX())
            + (c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());

    int rDistance = c.getR() * c.getR();

    if(Distance == rDistance)
        cout << "点在圆上\n";
    else if (Distance > rDistance)
        cout << "点在圆外\n";
    else
        cout << "点在圆内\n";
}

int main()
{
    Circle c;
    c.setR(10);
    Point center;
    center.setX(10);
    center.setY(0);
    c.setCenter(center);

    Point p;
    p.setX(10);
    p.setY(11);

    isInCircle(c, p);

    return 0;
}

C++学习笔记 (二)面向对象:封装、继承、多态_第51张图片

(4)构造函数用于初始化,析构函数用于清理

C++学习笔记 (二)面向对象:封装、继承、多态_第52张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第53张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第54张图片

 

 

以上能说明,在调用对象时会自动地调用构造与析构函数。

 

(5)构造函数分类及调用

C++学习笔记 (二)面向对象:封装、继承、多态_第55张图片

 

① 构造函数分类

C++学习笔记 (二)面向对象:封装、继承、多态_第56张图片

 

② 构造函数调用

函数调用的3种方法: 

C++学习笔记 (二)面向对象:封装、继承、多态_第57张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第58张图片

 

(6)拷贝构造函数调用时机

C++学习笔记 (二)面向对象:封装、继承、多态_第59张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第60张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第61张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第62张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第63张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第64张图片

 

(7)构造函数的调用规则

默认情况下,c++的每个类至少包含3个函数,构造、析构和拷贝构造函数

C++学习笔记 (二)面向对象:封装、继承、多态_第65张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第66张图片

 

(8)深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝

深拷贝:在·堆区重新申请空间,做拷贝操作

C++学习笔记 (二)面向对象:封装、继承、多态_第67张图片

注:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,以防止浅拷贝带来的问题。

 

(9)初始化列表 

 

C++学习笔记 (二)面向对象:封装、继承、多态_第68张图片

 

(10)类对象做为类成员

类里的成员可以是另一个类的对象,称此成员为对象成员

C++学习笔记 (二)面向对象:封装、继承、多态_第69张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第70张图片

 

(11)静态成员:变量,函数

C++学习笔记 (二)面向对象:封装、继承、多态_第71张图片

静态成员函数只能访问静态成员变量:

C++学习笔记 (二)面向对象:封装、继承、多态_第72张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第73张图片

静态成员变量有两种访问方式:

C++学习笔记 (二)面向对象:封装、继承、多态_第74张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第75张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第76张图片

 

(12)类内的成员变量与成员函数是分开存储的,只有非静态成员变量才属于类的对象上。

c++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置,每个空对象都具有独一无二的内存地址。

C++学习笔记 (二)面向对象:封装、继承、多态_第77张图片

(13)this指针!!!(和&引用一样,都是指向不可变)

特殊的对象指针,用来指向被调用的成员函数所属的对象。本质是指针常量,其指向不可改。

C++学习笔记 (二)面向对象:封装、继承、多态_第78张图片

如上图,因为this是指针,其指向对象p1,则解引用*this得到p1,即返回了对象本身。

作用:

①解决名称冲突(当形参和成员变量同名时,可以用this指针做区分)

②返回对象本身用*this

C++学习笔记 (二)面向对象:封装、继承、多态_第79张图片

可见并没有完成赋值,原因就是形参和成员变量名重复了,此时就可以用this指针解决:

C++学习笔记 (二)面向对象:封装、继承、多态_第80张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第81张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第82张图片

 

(14)空指针访问成员函数

C++学习笔记 (二)面向对象:封装、继承、多态_第83张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第84张图片

报错如下:

C++学习笔记 (二)面向对象:封装、继承、多态_第85张图片

修改如下,以保证代码健壮性:

C++学习笔记 (二)面向对象:封装、继承、多态_第86张图片

 

(15)常函数与常对象!!!

成员函数之后加const,称为常函数,其内不可修改成员属性。但当成员属性在声明时加了关键字mutable后,则可修改。

声明对象前加const,称为常对象,常对象只能调用常函数

注:在成员函数后加const,修饰的是this指针,令其指向的(this指针作为指针常量,其指向不可改,指向的值可改)也不可能改了。

C++学习笔记 (二)面向对象:封装、继承、多态_第87张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第88张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第89张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第90张图片

注:

const char* ptr == char const* ptr;  (可以直接改变指针指向,但不能直接改变指针指向的值);*ptr=*ss;

char* const ptr; (可以直接改变指针指向的值,但不能直接改变指针指向);ptr[0]='s';

但两者都可以通过改变所指向的指针的内容,来改变它的值。

const char* const ptr;(指向和指向的值都不可改)。

例1

C++学习笔记 (二)面向对象:封装、继承、多态_第91张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第92张图片

例2

C++学习笔记 (二)面向对象:封装、继承、多态_第93张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第94张图片

例3

C++学习笔记 (二)面向对象:封装、继承、多态_第95张图片

(16)友元 friend

让类外的一些函数或类,能够访问该类的私有成员!!!

3种实现:全局函数做友元,类做友元,成员函数做友元

1)全局函数做友元

C++学习笔记 (二)面向对象:封装、继承、多态_第96张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第97张图片

 

 

2)类做友元

C++学习笔记 (二)面向对象:封装、继承、多态_第98张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第99张图片

 

 

3)成员函数做友元

 

C++学习笔记 (二)面向对象:封装、继承、多态_第100张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第101张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第102张图片

 

(17)运算符重载

对已有的运算符做重新定义,赋予其另一种功能,以适应不同的数据类型

 

1)加号运算符重载:用成员函数实现,用全局函数实现

实现两个自定义数据类型相加

①用成员函数实现

C++学习笔记 (二)面向对象:封装、继承、多态_第103张图片

 

②用全局函数实现

C++学习笔记 (二)面向对象:封装、继承、多态_第104张图片

 

③重载运算符函数的重载

C++学习笔记 (二)面向对象:封装、继承、多态_第105张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第106张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第107张图片

 

2)左移运算符重载

重载左移运算符配合友元,可以实现输出自定义数据类型

C++学习笔记 (二)面向对象:封装、继承、多态_第108张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第109张图片

 

3)递增运算符重载

4)赋值运算符重载

5)关系运算符重载

6)函数调用运算符重载

函数调用运算符()也可以重载。由于重载后使用的方式非常像函数的调用,故称为仿函数。

仿函数没有固定写法,非常灵活。

 

5.继承

C++学习笔记 (二)面向对象:封装、继承、多态_第110张图片

(1)继承的方式

C++学习笔记 (二)面向对象:封装、继承、多态_第111张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第112张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第113张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第114张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第115张图片

 

(2)继承中的对象模型

C++学习笔记 (二)面向对象:封装、继承、多态_第116张图片

 

(3)继承中的构造与析构顺序

C++学习笔记 (二)面向对象:封装、继承、多态_第117张图片

 

(4)继承中,同名成员的处理方式

C++学习笔记 (二)面向对象:封装、继承、多态_第118张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第119张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第120张图片

 

 

 

(5)继承中,同名静态成员的处理方式

C++学习笔记 (二)面向对象:封装、继承、多态_第121张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第122张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第123张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第124张图片

 

(6)多继承

C++学习笔记 (二)面向对象:封装、继承、多态_第125张图片

 

(3)菱形继承

菱形继承带来的问题是子类会同时继承两份相同的数据,导致资源浪费以及毫无意义。可以用虚继承来解决这个问题。

C++学习笔记 (二)面向对象:封装、继承、多态_第126张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第127张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第128张图片

 

6.多态

(1)多态的基本语法

C++学习笔记 (二)面向对象:封装、继承、多态_第129张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第130张图片

如果想执行让猫说话,那么这个函数地址就不能提前绑定,而是要在运行阶段才绑定,要借助虚函数来实现

C++学习笔记 (二)面向对象:封装、继承、多态_第131张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第132张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第133张图片

注:重写不是重载。重写是指函数的返回值类型、函数名、参数列表都完全一致

 

(2)

C++学习笔记 (二)面向对象:封装、继承、多态_第134张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第135张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第136张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第137张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第138张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第139张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第140张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第141张图片

(3)纯虚函数与抽象类

C++学习笔记 (二)面向对象:封装、继承、多态_第142张图片

 

 

 

举例:

C++学习笔记 (二)面向对象:封装、继承、多态_第143张图片

   C++学习笔记 (二)面向对象:封装、继承、多态_第144张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第145张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第146张图片

 

(4)虚析构与纯虚析构

C++学习笔记 (二)面向对象:封装、继承、多态_第147张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第148张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第149张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第150张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第151张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第152张图片

举例:

C++学习笔记 (二)面向对象:封装、继承、多态_第153张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第154张图片

 

C++学习笔记 (二)面向对象:封装、继承、多态_第155张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第156张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第157张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第158张图片

C++学习笔记 (二)面向对象:封装、继承、多态_第159张图片

你可能感兴趣的:(C++)