1.类的“嵌套”:当类A包含类B的头文件时,就像类B被嵌套在类A中了,在类A中可以定义类B的对象并调用对象的公有成员。
2.常成员函数和常数据成员:在点类中举例说明。
以点类和线类为例:
点类
Coordinate.h
#ifndef COORDINATE_H
#define COORDINATE_H
class Coordinate
{
public:
//构造函数
Coordinate(int X = 0,int Y = 0);//默认值只需在声明时写出,定义时不用写
Coordinate(const Coordinate &coor);//拷贝构造函数
//数据封装函数
void setX(int _x);
void setY(int _y);//与下面同名。则对象变量会默认调用上面这个,如果没有上面这个,就会调用下面的。
void setY(int _y)const;//常成员函数。对象常量只能调用公有的常成员函数,其他非常的不可调用,所以调用下面的。
//常成员函数等价于void setY(const Coordinate* this,int _y);则当前对象(*this)不可修改
//一般功能函数
int getX();
int getY();
int getX()const;//const的Coordinate类对象(对象常量),只能调用有const修饰的函数
int getY()const;//如果没有上面的int getY(),那么对象变量也可以调用这个int getY()const
//析构函数
~Coordinate();
private:
const int m_iX; //常数据成员,一旦被赋初值(构造函数中)就不能再改变。
int m_iY;
};
#endif
Coordinate.cpp
#include"Coordinate.h"
#include<iostream>
using namespace std;
//构造函数(不用加const,常对象初始化时也会调用)
Coordinate::Coordinate(int X,int Y):m_iX(X)
{
//m_iX = X;常成员函数只能用列表初始化
m_iY = Y;
cout << "Coordinate(int X,int Y) " << m_iX << ","<< m_iY << endl;
}
Coordinate::Coordinate(const Coordinate &coor):m_iX(coor.m_iX)
{
//m_iX = coor.m_iX;
m_iY = coor.m_iY;
cout << "Coordinate(const Coordinate &coor)" << m_iX << ","<< m_iY << endl;
}
//数据封装函数
void Coordinate::setX(int _x)
{
//m_iY = _x;//报错
cout << "常数据成员不能改变值" << endl;
}
void Coordinate::setY(int _y)
{
m_iY = _y;
cout << "等价于void setY(Coordinate * this,int _y)" << endl;
}
void Coordinate::setY(int _y)const//常成员函数
{
//m_iY = _y;//报错
cout << "常成员函数不能修改对象的数据成员的值" << endl;
cout << "等价于void setY(const Coordinate * this,int _y)" << endl;
}
int Coordinate::getX()
{
return m_iX;
}
int Coordinate::getY()
{
return m_iY;
}
int Coordinate::getX()const
{
//this->setX(2);常成员函数内部不能调用普通的成员函数(因为此时对象是个常量,无法调用没有const修饰的函数)
return m_iX;
}
int Coordinate::getY()const
{
return m_iY;
}
//析构函数(不用加const,常对象初始化时也会调用)
Coordinate::~Coordinate()
{
cout << "~Coordinate()" << m_iX << ","<< m_iY <<endl;
}
线类
Line.h
#ifndef LINE_H
#define LINE_H
#include"Coordinate.h"
class Line
{
public:
//构造函数
Line();
Line(int x1,int y1,int x2,int y2);
Line(const Coordinate &A,const Coordinate &B);
//数据封装函数
void setA(int _x1,int _y1);
void setB(int _x2,int _y2);
//一般功能函数
void printline();
//析构函数
~Line();
private:
Coordinate m_CoorA; //取名一定要规范!!m_[类型][名字]。
Coordinate m_CoorB;
};
#endif
Line.cpp
#include"Line.h"
#include<iostream>
using namespace std;
//构造函数
Line::Line()
{
cout << "Line()" << endl;
}
//这里用set函数或者初始化列表都可以,我选择初始化列表
//因为如果Coordinate类的构造函数的所有参数必须赋值(即没有默认值;即没有默认构造函数)的话,那就只能用初始化列表的方式了,
//因为实例化Line类对象时,先会实例化两个Coordinate类的对象而且是没有赋初值的!
//若直接用set函数,是会报错的因为没有赋初值就没有真正被实例化并分配内存,此时只有通过Line构造函数的初始化列表给它们赋初值,使之真正实例化。
//Line::Line(int x1,int y1,int x2,int y2)
//{
// m_CoorA.setX(x1);
// m_CoorA.setY(y1);
// m_CoorB.setX(x2);
// m_CoorB.setY(y2);
// cout << "Line(int x1,int y1,int x2,int y2)" << endl;
//}
Line::Line(int x1,int y1,int x2,int y2):m_CoorA(x1,y1),m_CoorB(x2,y2)
{
cout << "Line(int x1,int y1,int x2,int y2)" << endl;
}
Line::Line(const Coordinate &A,const Coordinate &B):m_CoorA(A),m_CoorB(B)
{
/*m_CoorA = A;因为m_CoorA和B里都有常数据成员,不可直接赋值,只能用列表初始化
m_CoorB = B;*/
cout << "Line(Coordinate A,Coordinate B)" << endl;
}
//数据封装函数
void Line::setA(int _x1,int _y1)
{
m_CoorA.setX(_x1);
m_CoorA.setY(_y1);
}
void Line::setB(int _x2,int _y2)
{
m_CoorB.setX(_x2);
m_CoorB.setY(_y2);
}
//一般功能函数
void Line::printline()
{
cout << "(" << m_CoorA.getX() << "," << m_CoorA.getY() << ")" <<endl;
cout << "(" << m_CoorB.getX() << "," << m_CoorB.getY() << ")" <<endl;
}
//析构函数
Line::~Line()
{
cout << "~Line()" << "(" << m_CoorA.getX() << "," << m_CoorA.getY() << ") ";
cout << "(" << m_CoorB.getX() << "," << m_CoorB.getY() << ")" <<endl;
}
测试程序
demo.cpp
#include<iostream>
#include<stdlib.h>
#include"Coordinate.h"
#include"Line.h"
using namespace std;
int main()
{
//点实例化
Coordinate p1(3,4);
Coordinate p2;
Coordinate p3(8);
Coordinate *pp = new Coordinate();//加不加括号都对,堆内申请
delete pp;
Coordinate *PP2 = &p2;//栈内申请
//常对象测试
const Coordinate p4(1,1);
p4.setY(3); //调用的会是带const字样的setY,因为p4是常对象,只能调用常成员函数
//p4.setX(1);//报错,因为setX非常成员函数
cout << "(" <<p4.getX() << "," <<p4.getY() << ")" << endl;
//调用封装函数
p2.setX(3);
p2.setY(7);
//线段实例化
Line *p = new Line(p1,p2);
Line l1(0,0,6,8);
Line l2;
//调用封装函数
l2.setA(1,2);
l2.setB(3,3);
//打印功能
l1.printline();
p->printline();
l2.printline();
delete p;
p = NULL;
system("pause");
return 0;
}//结果比想象的多了两个析构函数,不懂。。已解决,修改了构造函数从Line(Coordinate A,Coordinate B)变成了Line(const Coordinate &A,const Coordinate &B)。
//类似于拷贝函数。改前,调用构函时,先会构造A、B这两个形参来接收p1、p2的值(而且是调用两次拷贝构造函数给AB赋值),Line构函返回后AB被释放,所以会出现两次析构函数。
//而加了const(用于保护原引用对象不被改变)和引用&后,引用是对象的别名,不会安排新内存构造新对象作形参,所以就没有多出来的两个构造函数和析构函数了。