7-C++远征之封装篇[下]-学习笔记

作者: 天涯明月笙 | 来源:发表于2018-07-21 22:04 被阅读62次

C++远征之封装篇(下)

c++封装概述

下半篇依然围绕类 & 对象进行展开

将原本学过的简单元素融合成复杂的新知识点。

  • 对象 + 数据成员 = 对象成员(对象作为数据成员)
  • 对象 + 数组 = 对象数组(一个数组中的每个元素都是对象)
  • 深拷贝 & 浅拷贝 (对象之间彼此赋值,彼此拷贝)
  • 对象指针(操作对象) & 对象指针成员
  • this指针
  • const + 对象 -> 常对象
  • const + 函数 -> 常成员函数
  • const + 对象成员 -> 常对象成员

设计了一个精巧的案例,走迷宫。

c++ 对象数组

如何实例化一个对象?实例化对象对于程序是很重要的,只有实例化了对象才能访问成员函数和数据成员。

某些情况下我们往往需要实例化一组对象。比如:我们想实例化出一个50人的班的学生。

堆栈

栈区实例化对象数组,会分配相应的内存,系统会自动管理。每一个内存中保存着x,y
堆区分配相应内存,p 与 p[0] 是等价的。

C++对象数组实践代码

要求

2-2-InstanceArray

Coordinate.h

class Coordinate
{
public:
    Coordinate();
    ~Coordinate();
public:
    int m_iX;
    int m_iY;
};

coordinate.cpp

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate()
{
    cout << "Coordinate" << endl;

}
Coordinate::~Coordinate()
{
    cout << "~Coordinate" << endl;
}

main.cpp

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Coordinate.h"
using namespace std;

int main(void)
{
    Coordinate coor[3];
    coor[0].m_iX = 3;
    coor[0].m_iY = 5;

    Coordinate *p = new Coordinate[3];
    p->m_iX = 7;
    p[0].m_iY = 9;

    p++;
    p->m_iX = 11;
    p[0].m_iY = 13;//此时因为上面p++。p已经指向第二个地址了

    p[1].m_iX = 15;//此时p指向第三个元素

    p++;
    p->m_iY = 17;//此时p指向第三个元素

    for (int i = 0; i < 3; i++)
    {
        cout << coor[i].m_iX << " coor x&y " << coor[i].m_iY << endl;

    }
    for (int j = 0; j < 3; j++)
    {
        //cout << "p_x" << p[j].m_iX << endl;
        //cout << "p_y" << p[j].m_iY << endl;
        cout << "p_x" << p->m_iX << endl;
        cout << "p_y" << p->m_iY << endl;
        p--;
    }

    p++;//因为上面p=-1时才退出了循环。因此释放时已经不是原来那段内存了。

    delete []p;
    p = NULL;
    system("pause");
    return 0;
}
要求

2-6-ObjectMember

Coordinate.h :

class Coordinate
{
public:
    Coordinate();
    ~Coordinate();
public:
    int getX();
    void setX(int x);

    int getY();
    void setY(int y);
private:
    int m_iX;
    int m_iY;
};

Coordinate.cpp :

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate()
{
    cout << "Coordinate" << endl;

}
Coordinate::~Coordinate()
{
    cout << "~Coordinate" << endl;
}

int Coordinate::getX() {
    return m_iX;
}
void Coordinate::setX(int x) {
    m_iX = x;
}
int Coordinate::getY(){
    return m_iY;
}
void Coordinate::setY(int y) {
    m_iY = y;
}

Line.h :

#include "Coordinate.h"

class Line {
public:
    Line();
    ~Line();
    void setCoorA(int x, int y);
    void setCoorB(int x, int y);
    void printInfo();
private:
    Coordinate m_coorA;
    Coordinate m_coorB;
};

Line.cpp :

#include <iostream>
#include "Line.h"

using namespace std;

Line::Line() {
    cout << "Line()" << endl;
}
Line::~Line() {
    cout << "~Line()" << endl;
}
void Line::setCoorA(int x, int y) {
    m_coorA.setX(x);
    m_coorA.setX(y);
}
void Line::setCoorB(int x, int y) {
    m_coorB.setX(x);
    m_coorB.setY(y);
}
void Line::printInfo() {
    cout << "(" <<m_coorA.getX()<< "," <<m_coorA.getY()<< ")" << endl;
    cout << "(" << m_coorB.getX()<< "," << m_coorB.getY()<< ")" << endl;
}

main.cpp

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Line.h"

using namespace std;

int main(void)
{
    Line *p = new Line();

    delete p;
    p = NULL;
    system("pause");
    return 0;
}
要求

说明一下某些场合深拷贝的实用性。

3-2-ShallowCopy

浅拷贝代码:

Array.h

class  Array
{
public:
     Array();
     Array(const Array& arr);
    ~ Array();

    int getCount();
    void setCount(int val);
private:
    int m_iCount;
};

Array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array()
{
    cout << "Array()" << endl;
}

Array::Array(const Array& arr) {
    m_iCount = arr.m_iCount;
    cout << "Array(&)" << endl;
}

Array::~Array() {
    cout << "~Array()" << endl;
}

void Array::setCount(int c) {
    m_iCount = c;
}
int Array::getCount() {
    return m_iCount;
}

main.cpp:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
    Array arr1;
    arr1.setCount(5);

    Array arr2 = arr1;

    cout << "arr2,count:" <<arr2.getCount() << endl;
    system("pause");
    return 0;
}
堆中

p指向m_iX,访问方式为p->m_iX;
*p变成一个对象,采用.访问其中元素。

具体示例代码:

int main(void)
{
    Coordinate *p = new Coordinate;
    p -> m_iX = 10;  //(*p).m_iX =10;
    p -> m_iY = 20;  //(*p).m_iY =20;
    delete p;
    p = NULL;
    return 0;
}
  • new 会自动调用对象的构造函数;
  • C语言中的 malloc 则不会调用相关对象的构造函数,只是分配内存。

C++对象指针实践:

要求

4-2-ObjectPointer

Coordinate.h

class Coordinate
{
public:
    Coordinate();
    ~Coordinate();
    int m_iX;
    int m_iY;
};

Coordinate.cpp

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate()
{
    cout << "Coordinate()" << endl;
}

Coordinate::~Coordinate()
{
    cout << "~Coordinate()" << endl;
}

main.cpp:

#include <iostream>
#include "Coordinate.h"
#include <stdlib.h>

using namespace std;

int main()
{
    // 使用对象指针指向内存,两种方法

    // 堆中实例化
    Coordinate *p1 = NULL;
    p1 = new Coordinate; //因为有默认构造函数,括号可写可不写
    Coordinate *p2 = new Coordinate(); //方法2

    p1->m_iX = 10;
    p1->m_iY = 20; // 指针方式
    (*p2).m_iX = 30; //*p2使p2变成了一个对象
    (*p2).m_iY = 40;

    cout << (*p1).m_iX + (*p2).m_iX << endl;
    cout << p1->m_iY + p2-> m_iY << endl;

    delete p1;
    p1 = NULL;
    delete p2;
    p2 = NULL;

    system("pause");
    return 0;
}
对象成员指针sizeof

创建时line对象中只有两个占4字节的指针。
而实例化出的两个对象在堆中;销毁时,先销毁堆中的,再释放line对象。

对象成员指针实践

要求

4-5-ObjectMemberPointer

Coordinate.h

class Coordinate
{
public:
    Coordinate(int x, int y);
    ~Coordinate();
public:
    int getX();
    int getY();
private:
    int m_iX;
    int m_iY;
};

Coordinate.cpp

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate(int x,int y)
{
    m_iX = x;
    m_iY = y;
    cout << "Coordinate()"<<m_iX<<","<<m_iY << endl;

}
Coordinate::~Coordinate()
{
    cout << "~Coordinate()" << m_iX << "," << m_iY << endl;
}

int Coordinate::getX() {
    return m_iX;
}
int Coordinate::getY(){
    return m_iY;
}

Line.h:

#include "Coordinate.h"

class Line {
public:
    Line(int x1,int y1,int x2,int y2);
    ~Line();
    void setCoorA(int x, int y);
    void setCoorB(int x, int y);
    void printInfo();
private:
    Coordinate *m_pCoorA;
    Coordinate *m_pCoorB; //这是一个坐标类的对象指针。它只是一个指针。
};

Line.cpp:

#include "Line.h"
#include <iostream>
using namespace std;

Line::Line(int x1,int y1,int x2,int y2){
    m_pCoorA = new Coordinate(x1, y1);
    m_pCoorB = new Coordinate(x2, y2);
    cout << "Line()" << endl;
}
Line::~Line() {
    delete m_pCoorA;
    m_pCoorA = NULL;
    delete m_pCoorB;
    m_pCoorB = NULL;
    cout << "~Line()" << endl;
}
void Line::printInfo() {
    cout << "("<<(*m_pCoorA).getX()<<","<< (*m_pCoorA).getY()<< ")" << endl;
    cout << "(" << m_pCoorB->getX() << "," << m_pCoorB->getY() << ")" << endl;
}

main.cpp:

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Line.h"
using namespace std;

int main(void)
{
    Line *p = new Line(1,2,3,4);
    p->printInfo();

    delete p;
    p = NULL;

    cout << sizeof(p) << endl;
    cout << sizeof(Line) << endl;
    system("pause");
    return 0;
}

运行结果:

this

this表达什么地址,取决于当前所在作用域。这样就可以标记出自身的成员,与参数可以分清哪个是哪个了。

class Array
{
    public:
        Array(int len){this->len = len;}//对
        int getLen(){return len;}
        void setLen(int len){this->len = len;}//对
    private:
        int len;
}

对象结构:

对象结构
  • 存在多个对象,成员函数只有代码区内的一份。

又没有传递参数,成员函数如何确定该调用哪个对象的数据成员?

  • 成员函数如何访问到对应对象的数据成员?
class Array
{
    public:
        Array(T *this,int len){this->len = len;}//对
        int getLen(T *this){return this->len;}
        void setLen(T *this,int len){this->len = len;}//对
    private:
        int len;
}
this指针
  • 通过this来实现分辨不同的arr。
  • 编译器自动的为每一个成员函数的参数列表都自动加上了this指针。

this指针在参数列表中的位置(代码实践)

要求:

this代码实践

正常版本1:

4-7-ThisPointerPosition

Array.h

class  Array
{
public:
    Array(int len);
    ~ Array();

    void printAddr();
    void printArr();
    int getLen();
    void setLen(int val);
    void printInfo();
private:
    int m_iLen;
};

Array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array(int len)
{
    m_iLen = len;
    cout << "Array()" << endl;
}
Array::~Array() {
    cout << "~Array()" << endl;
}

void Array::setLen(int len) {
    m_iLen = len;
}
int Array::getLen() {
    return m_iLen;
}

void Array::printInfo() {

}

main.cpp:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
    Array arr1(10);

    system("pause");
    return 0;
}
隐藏的参数this指针

实际成员函数有一个隐藏的参数,this指针。

const修饰的指针变成常指针

this指针变成了一个常指针,通过常指针改变数据,显然是不被允许的。

互为重载:

    void changeX() const;
    void changeX(); //互为重载

Q:当直接调用:coordinate.changeX()到底调用的是哪一个呢?

A:调用的是普通的不带const的。

Q: 那么想调用那个带const的如何写?

A:代码如下

int main(void)
{
    // 实例化对象时用const修饰这个对象
    const Coordinate coordinate(3,5);//常对象
    coordinate.changeX(); // 调用的是常成员函数
    return 0;
}

常对象调用的是常成员函数。
普通对象调用的是普通成员函数。

常对象成员与常成员函数代码实践

要求

5-2-ConstantMemberFunction

Coordinate.h :

class Coordinate
{
public:
    Coordinate(int x, int y);
    ~Coordinate();
public:
    int getX() const;//此处声明该成员函数为常成员函数
    void setX(int x); // 相当于setX(Coordinate *this, int x)
    int getY() const;//同上
    void setY(int y);
private:
    int m_iX;
    int m_iY;
};

Coordinate.cpp

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate(int x, int y)
{
    m_iX = x;
    m_iY = y;
    cout << "Coordinate()" << m_iX << "," << m_iY << endl;

}
Coordinate::~Coordinate()
{
    cout << "~Coordinate()" << m_iX << "," << m_iY << endl;
}

int Coordinate::getX() const{
    return m_iX;
}
void Coordinate::setX(int x) { 
    m_iX = x;
}
int Coordinate::getY() const{
    return m_iY;
}
void Coordinate::setY(int y) {
    m_iY = y;
}

Line.h:

#include "Coordinate.h"

class Line {
public:
    Line(int x1, int y1, int x2, int y2);
    ~Line();
    void setCoorA(int x, int y);
    void setCoorB(int x, int y);
    void printInfo();
    void printInfo() const;//互为重载

private:
    const Coordinate m_coorA; // Coordinate const m_coorA;
    Coordinate m_coorB;
};

Line.cpp:

#include "Line.h"
#include <iostream>
using namespace std;

Line::Line(int x1, int y1, int x2, int y2) :m_coorA(x1, y1), m_coorB(x2, y2) {
    cout << "Line()" << endl;
}
Line::~Line() {
    cout << "~Line()" << endl;
}
void Line::setCoorA(int x, int y) {
    //m_coorA.setX(x); // 出现问题: 此时相当于在setX中传递了一个this指针
    //m_coorA.setX(y);
}
void Line::setCoorB(int x, int y) {
    m_coorB.setX(x);
    m_coorB.setY(y);
}
void Line::printInfo() {
    cout << "printInfo()" << endl;
    cout << "(" << m_coorA.getX() << "," << m_coorA.getY() << ")" << endl;
    cout << "(" << m_coorB.getX() << "," << m_coorB.getY() << ")" << endl;

}
void Line::printInfo() const{
    cout << "printInfo() const" << endl;
    cout << "(" << m_coorA.getX() << "," << m_coorA.getY() << ")" << endl;
    cout << "(" << m_coorB.getX() << "," << m_coorB.getY() << ")" << endl;
}

main.cpp

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Line.h"
using namespace std;

int main(void)
{
    Line line(1, 2, 3, 4);
    line.printInfo();//调用的是普通的

    const Line line2(1, 2, 3, 4);
    line2.printInfo();//调用的是常成员函数
    
    system("pause");
    return 0;
}
出入为一个

架构描述

涉及两个类: 迷宫类(MazeMap)& 走迷宫的人(Person)

二维数组:

1代表墙,0代表路,自己决定。

1墙0路

迷宫类(MazeMap)

数据成员:

- 墙壁字符
- 通路字符
- 迷宫数组

成员函数:

- 构造函数
- 数据封装函数
- 迷宫回执函数
- 迷宫边界检查函数

人类(MazePerson)

数据成员:

- 人的字符
- 人的朝向
- 人当前位置(设置在入口)
- 人前一个位置 (人走动,前位置抹掉,后一个位置绘制)
- 人的速度

成员函数:

- 构造函数
- 数据封装函数
- 向不同方向前进的函数(上下左右)
- 转弯函数
- 开始函数

控制台动画控制:

/*
 * 函数名称:gotoxy
 * 函数功能:确定控制台中字符的输出位置
 * 函数列表:
 *      x:横坐标
 *      y:纵坐标
 */

void MazePerson::gotoxy(int x, int y)   
{   
    COORD cd;    
    cd.X   =   x; 
    cd.Y   =   y;
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  
    SetConsoleCursorPosition(handle,cd); // 把光标定位到相应位置上    
};

首先需要定义一个迷宫,迷宫是一个二维数组,WaLL是墙,Road是路。

绘制迷宫cout就可以了。有了迷宫的二维数组,先实例化一个迷宫对象,通过setMazeMap函数将
二维数组设置进去,SetMazeWall告诉计算机墙用什么表示。设置好之后绘制迷宫。

走迷宫的人,设置人的位置位于入口。设置人的速度,设置人的字符形状。

人开始运动。

注意事项:

  • 枚举类型:方向(上下左右)
  • 常量定义:宏定义 & const

成就感源于克服困难

迷宫代码实现

未完待续, 之后补充。

相关文章

网友评论

  • 隐抑:很遗憾,没看懂
    天涯明月笙:@隐抑 c++是挺难的,要学的很多,得耐着性子慢慢学。

本文标题:7-C++远征之封装篇[下]-学习笔记

本文链接:https://www.haomeiwen.com/subject/kcmcmftx.html