学习教程:https://www.imooc.com/learn/405
对象数组
举例:
Coordinate coord[3]; //在栈上实例化一个对象数组
Coordinate *p = new Coordinate[3]; //在堆中实例化一个对象数组,这里是[3],会调用3次构造函数
数组被实例化完成之后,每一个元素都可以访问其各自的数据成员
//在栈上实例化的:
coord[1].m_iX = 10;
//在堆上实例化的:
p[0].m_iY = 20; //或者:p->m_iY = 20;
在堆中实例化的,用完之后要销毁:
delete []p; //销毁的过程中会调用三次析构函数
p = NULL;
编码示例:
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;
}
demo.cpp
#include <iostream>
#include "Coordinate.h"
using namespace std;
int main()
{
Coordinate coor[3]; //从栈上实例化数组
coor[0].m_iX = 1; //赋值
coor[0].m_iY = 2;
coor[1].m_iX = 11;
coor[1].m_iY = 22;
coor[2].m_iX = 111;
coor[2].m_iY = 222;
Coordinate *p = new Coordinate[3];
//以下用两种方式访问数组第一个元素
p->m_iX = 3;
p[0].m_iY = 4;
p++; //此时p指向数组的第二个元素
p->m_iX = 5; //此时访问到的是数组的第二个元素
p[0].m_iY = 6; //此时这样子访问的也是数组的第二个元素,且不能再用这个方式访问数组的第一个元素,[]中不能是复数
p[1].m_iX = 7; //此时访问的是数组的第三个元素
p++; //此时p指向数组的第三个元素
p->m_iY = 8; //此时是给数组的第三个元素的成员赋值
//以下遍历数组:
int i;
for (i = 0; i < 3; i++)
{
cout << "coor_x" << coor[i].m_iX << endl;
cout << "coor_y" << coor[i].m_iY << endl;
}
for (i =0; i < 3; i++)
{
cout << "p_x" << p->m_iX << endl; //因为前面已经做了两次p++,现在p已经指向数组最后一个元素
cout << "p_y" << p->m_iY << endl;
p--; //从后往前遍历
}
p++; //上面的for循环,做最后一次遍历(即遍历第一个元素)后,又做了一次p--,此时p指向数组第一个元素的前一个。这样子是不可以直接delete 的,要让p指回数组第一个元素
delete []p;
p = NULL;
return 0;
}
对象成员
举例:
要实现描述一条线段,需要有坐标点A、B,和线段。定义两个类,一个坐标类,有A、B两个对象,定义一个线段类
实例化对象时,先实例化点A,再实例化点B,再实例化线段,销毁顺序为实例化顺序的逆序。
编码示例1:
Coordinate.h
class Coordinate
{
public:
Coordinate();
~Coordinate();
void setX(int x);
int getX();
void setY(int y);
int getY();
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;
}
void Coordinate::setX(int x)
{
m_iX = x;
}
int Coordinate::getX()
{
return m_iX;
}
void Coordinate::setY(int y)
{
m_iY = y;
}
int Coordinate::getY()
{
return m_iY;
}
Line.h
#include "Coordinate.h"
class Line
{
public:
Line();
~Line();
void setA(int x, int y); //线段A
void setB(int x, int y); //线段B
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::setA(int x, int y)
{
m_coorA.setX(x);
m_coorA.setY(y);
}
void Line::setB(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;
}
demo.cpp
#include <iostream>
#include "Coordinate.h"
#include "Line.h"
using namespace std;
int main()
{
Line *p = new Line();
delete p;
p = NULL;
return 0;
}
先调用两次坐标类的构造函数,再调用线段类的构造函数,说明先创建两个坐标类的对象,即A点和B点,然后再调用线段的对象(该对象是在A点和B点初始化完成之后才创建的)。
销毁时,先调用线段类的析构函数,再调用坐标类的析构函数,与创建对象的顺序相反。
示例2:
Coordinate.h
class Coordinate
{
public:
Coordinate(int x, int y);
~Coordinate();
void setX(int x);
int getX();
void setY(int y);
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; // 打印X和Y是为了根据输出判断先调用A点的构造函数还是先调用B点的构造函数(以知道先实例化A还是B)
}
Coordinate::~Coordinate()
{
cout << "~Coordinate" << m_iX << " , " << m_iY << endl;// 打印X和Y是为了根据输出判断先调用A点的析构函数还是先调用B点的析构函数
}
void Coordinate::setX(int x)
{
m_iX = x;
}
int Coordinate::getX()
{
return m_iX;
}
void Coordinate::setY(int y)
{
m_iY = y;
}
int Coordinate::getY()
{
return m_iY;
}
Line.h
class Line
{
public:
Line(int x1,int y1, int x2, int y2);
~Line();
void setA(int x, int y); //线段A
void setB(int x, int y); //线段B
void printinfo();
private:
Coordinate m_coorA;
Coordinate m_coorB;
};
Line.cpp
#include <iostream>
#include "Line.h"
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::setA(int x, int y)
{
m_coorA.setX(x);
m_coorA.setY(y);
}
void Line::setB(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;
}
demo.cpp
#include <iostream>
#include "Coordinate.h"
#include "Line.h"
using namespace std;
int main()
{
Line *p = new Line(1,2,3,4);
p->printinfo();
delete p;
p = NULL;
return 0;
}
先实例化A点,再实例化B点,再实例化线段。销毁时,先销毁线段,再销毁B点,最后销毁A点
由示例可知,若坐标类有一个默认构造函数(不带参数的构造函数),即示例1 Coordinate.h中Coordinate();
,就可以在实例化线段对象时,不使用初始化列表(Line.cpp中即Line::Line(int x1, int y1, int x2, int y2):m_coorA(x1,y1),m_coorB(x2,y2) //用了初始化列表
不用初始化列表也是可以的)但如示例2 Coordinate.h中Coordinate(int x, int y);
,构造函数要求要有参数传入,在实例化线段类的时候,就必须使用初始化列表将相应的值传给坐标类
实例化对象A时,如果对象A有对象成员B,那么先执行对象B的构造函数,再执行A的构造函数。
实例化对象A时,如果对象A有对象成员B,那么先执行对象B的构造函数,再执行A的构造函数。
如果对象A中有对象成员B,那么销毁对象A时,先执行对象A的析构函数,再执行B的析构函数。
如果对象A中有对象成员B,对象B没有默认构造函数,那么对象A必须在初始化列表中初始化对象B。