C++封装 之 常对象成员 和 常成员函数
常对象成员 和 常成员函数
定义两个类:
坐标类:Coordinate
数据成员:横坐标m_iX、纵坐标m_iY
成员函数:构造函数、析构函数、数据封装函数
线段类:Line
数据成员:点A m_CoorA、点B m_CoorB
成员函数:构造函数、析构函数、数据封装函数、信息打印函数
源代码
#include<iostream>
using namespace std;
/***************** 定义 Coordinate 类 *****************/
class Coordinate{
public:
Coordinate(int x, int y);
~Coordinate();
void setX(int x);
void setY(int y);
int getX();
int getY();
private:
int m_iX;
int m_iY;
};
/***************** 定义 Line 类 *****************/
class Line{
public:
Line(int x1, int y1, int x2, int y2);
~Line();
void setA(int x, int y);
void setB(int x, int y);
void printInfo();
private:
Coordinate m_CoorA; // 对象成员
Coordinate m_CoorB; // 对象成员
};
/********************** Coordinate类的成员函数 ***************************/
Coordinate::Coordinate(int x, int y){
m_iX = x;
m_iY = y;
}
Coordinate::~Coordinate(){
}
void Coordinate::setX(int x){
m_iX = x;
}
void Coordinate::setY(int y){
m_iY = y;
}
int Coordinate::getX(){
return m_iX;
}
int Coordinate::getY(){
return m_iY;
}
/********************** Line类的成员函数 ***************************/
Line::Line(int x1, int y1, int x2, int y2):m_CoorA(x1, y1),m_CoorB(x2, y2){ //必须使用初始化列表初始化对象成员
}
Line::~Line(){
}
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 << "A = ("<< m_CoorA.getX() << "," << m_CoorA.getY() << ")" << endl;
cout << "B = ("<< m_CoorB.getX() << "," << m_CoorB.getY() << ")" << endl;
}
/************************** 测试主函数 *******************************/
int main(){
Line *p = new Line(1,2,3,4); // 实例化对象时,直接传参数
p->printInfo(); //打印
delete p; // 销毁Line对象 */
p = NULL; //置空指针
system("pause");
return 0;
}
运行结果
A = (1,2)
B = (3,4)
常对象成员
改造上面的源代码,将Line类的数据成员m_CoorA修改为常对象成员:
class Line{
public:
Line(int x1, int y1, int x2, int y2);
~Line();
void setA(int x, int y);
void setB(int x, int y);
void printInfo();
private:
const Coordinate m_CoorA; // 常对象成员 , 也可以写为 Coordinate const m_CoorA;
Coordinate m_CoorB; // 对象成员
};
报错的位置
void Line::setA(int x, int y){
m_CoorA.setX(x); //报错
m_CoorA.setY(y); //报错
}
void Line::printInfo(){
cout << "A = ("<< m_CoorA.getX() << "," << m_CoorA.getY() << ")" << endl; //报错
cout << "B = ("<< m_CoorB.getX() << "," << m_CoorB.getY() << ")" << endl;
}
报错原因分析:
void setX(int x){
}
在编译时相当于:
void setX(Coordinate *this, int x){
}
成员函数setX()默认的this指针指向的对象既有读权限、也有写权限,而m_CoorA是常对象成员,没有写权限,所以 m_CoorA.setX(x)错误。
常成员函数
上面错误的解决办法:将普通成员函数修改为常成员函数。即setX()、setY()、getX()、getY()等要修改为常成员函数。
常成员函数不能修改数据成员的值,所以setX()和setY()修改为常成员函数是没有意义的,只能修改getX()和getY()。
getX()和getY()声明和定义的地方都要加const:
class Coordinate{
public:
Coordinate(int x, int y);
~Coordinate();
void setX(int x) ;
void setY(int y);
int getX() const; //常成员函数声明
int getY() const; //常成员函数声明
private:
int m_iX;
int m_iY;
};
int Coordinate::getX() const{ //常成员函数定义,注意const前面应该有一个空格,否则编译不通过
return m_iX;
}
int Coordinate::getY() const{ //常成员函数定义
return m_iY;
}
编译时,
int getX() const; //常成员函数声明
相当于
int getX(const Coordinate *this);
也就是说,常成员函数getX()参数列表中的this指针是没有写权限的,函数printInfo()中传入的正好就是没有写权限的常对象成员的this指针,函数printInfo()中的报错解决,但set()中的报错还没有解决,直接注释掉。
互为重载
常成员函数与普通成员函数同名的情况下,可以互为重载
class Line{
public:
Line(int x1, int y1, int x2, int y2);
~Line();
//void setA(int x, int y);
void setB(int x, int y);
void printInfo();
void printInfo() const; //常成员函数
private:
const Coordinate m_CoorA;
Coordinate m_CoorB;
};
void Line::printInfo(){
cout << "A = ("<< m_CoorA.getX() << "," << m_CoorA.getY() << ")" << endl; //报错,将getX()和getY()修改为常成员函数后错误解决
cout << "B = ("<< m_CoorB.getX() << "," << m_CoorB.getY() << ")" << endl;
}
void Line::printInfo() const{
cout << "A = ("<< m_CoorA.getX() << "," << m_CoorA.getY() << ")" << endl; //报错,将getX()和getY()修改为常成员函数后错误解决
cout << "B = ("<< m_CoorB.getX() << "," << m_CoorB.getY() << ")" << endl;
}
//上面代码编译通过且正确运行
函数重载区分
两个重载的成员函数(函数名、参数个数、参数类型都相同,区别在于其中一个成员函数的this指针是用const修饰的)如何分别调用的是哪一个函数呢?
实例化对象的时候也加const修饰符
int main(){
Line *p = new Line(1,2,3,4);
p->printInfo(); //打印发现,调用的是普通的成员函数printInfo()
Line const *p1 = new Line(1,2,3,4); //加const
p1->printInfo(); //打印发现,调用的是常成员函数printInfo() const
delete p;
p = NULL;
system("pause");
return 0;
}