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

1.内存

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

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

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

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

 

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

 

 

 

 

 

 

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

 

2.引用

作用:用来给变量起别名

数据类型 &别名 = 原名;

 

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

 

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

 

(2)引用做函数参数

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

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

 

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

 

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

 

(5)常量引用

 

3.函数

(1)默认参数

 

(2)占位参数

 

(3)函数重载

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

需满足3个条件:

①同一个作用域   

②函数名称相同       

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

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

函数重载注意事项:

 

4.类和对象

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

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

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

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

访问权限有3种:

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

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

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

 

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

 

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

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

 

#include <iostream>
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;
}

#include <iostream>
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;
}

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

 

 

 

 

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

 

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

 

① 构造函数分类

 

② 构造函数调用

函数调用的3种方法: 

 

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

 

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

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

 

 

(8)深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝

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

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

 

(9)初始化列表 

 

 

(10)类对象做为类成员

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

 

 

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

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

 

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

 

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

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

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

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

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

作用:

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

②返回对象本身用*this

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

 

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

报错如下:

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

 

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

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

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

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

 

 

 

 

(16)友元 friend

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

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

1)全局函数做友元

 

 

2)类做友元

 

 

3)成员函数做友元

 

 

(17)运算符重载

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

 

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

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

①用成员函数实现

 

②用全局函数实现

 

③重载运算符函数的重载

 

2)左移运算符重载

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

 

3)递增运算符重载

4)赋值运算符重载

5)关系运算符重载

6)函数调用运算符重载

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

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

 

5.继承

(1)继承的方式

 

 

(2)继承中的对象模型

 

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

 

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

 

 

 

 

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

 

(6)多继承

 

(3)菱形继承

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

 

 

 

6.多态

(1)多态的基本语法

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

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

 

(2)

(3)纯虚函数与抽象类

 

 

 

举例:

   

 

(4)虚析构与纯虚析构

举例:

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值