0 类和对象
C++面向对象的三大特性:封装、继承、多态。
C++中万物皆对象,对象包含属性(成员变量/成员属性)和行为(成员函数/成员方法)。
1 封装的意义
封装的意义:
(1)将属性和行为作为一个整体,表征现实的事物;
(2)对属性和行为进行权限控制。
访问权限包括3种:
public
:公共权限——成员在类中和类外均可访问。
protected
:保护权限——成员在类中可访问,类外不可访问;子类可访问父类的保护成员。
private
:私有权限——成员在类中可访问,类外不可访问;子类不可访问父类的私有成员。
注1:
protected
和private
的主要区别在于继承方面,即子类是否可以访问父类的相关成员:protected
子类可访问父类的保护成员;private
子类不可访问父类的私有成员。
注2:类中的函数内部,仍属于类中,可访问任意权限的类成员。
注3:类class的默认权限为私有private
。
注4:类的作用域
属于类内
,如类型::成员
,可访问类中的私有成员或私有构造函数。
类的定义:
class 类名{
访问权限:
属性/行为
};
实例化:通过类创建一个具体的对象。
示例:
#include <iostream>
using namespace std;
const double PI = 3.14;
class Circle {
private: //访问权限:私有权限(类中可访问,类外不可访问)
/* 类的属性:成员变量 */
int radius;
public: //访问权限:公共权限(类中和类外均可访问)
/* 类的行为:成员函数 */
void setRadius(int r){
radius = r;
}
double calculateArea() {
return PI * radius * radius;
}
};
int main() {
//实例化对象
Circle c;
c.setRadius(1);
double area = c.calculateArea();
cout << area << endl;
return 0;
}
2 结构体struct和类class区别
C++中,结构体struct
和类class
均可表征一个类,唯一区别在于默认的访问权限不同。
(1)结构体struct的默认权限为公共public
;
(2)类class的默认权限为私有private
。
示例:
/*
结构体的默认权限是公共public
类的默认权限是私有private
*/
class Class {
int field; //默认是私有,类外不可访问
};
struct Struct {
int field; //默认是公有,结构体外科访问
};
int main() {
/* 结构体的默认权限是公共public */
Struct s;
s.field = 1; //可访问
/* 类的默认权限是私有private */
Class c;
//c.field = 2; //报错:Class::field不可访问
return 0;
}
3 成员属性设置为私有
将所有成员属性设置为私有的优点:
(1)可使用getter/setter函数
控制读写权限,避免成员属性被外部直接访问或修改;
(2)对于写权限,可使用逻辑判断语句校验写入数据的有效性。
示例:
#include <iostream>
using namespace std;
#include <string>
class Person {
private:
string _name; //设置读写权限
int _age; //设置读写权限
public:
/* 使用 getter/setter函数 控制读写权限 */
void setName(string name) {
_name = name;
}
string getName() {
return _name;
}
void setAge(int age) {
/* 校验写入数据的有效性 */
if (age < 0 || age > 120) {
cout << "输入的年龄有误" << endl;
_age = 0;
return;
}
_age = age;
}
int getAge() {
return _age;
}
};
int main() {
Person p;
p.setName("Tom");
cout << "姓名:" << p.getName() << endl;
//p.setAge(200); //数据不在有效范围
p.setAge(20);
cout << "年龄:" << p.getAge() << endl;
return 0;
}
4 封装特性的练习案例:点和圆的位置关系
创建圆类(Circle)和点类(Point),根据点与圆心的距离判断点和圆的位置关系。
重点:
(1)不同类的分文件编写:头文件和源文件中成员函数的写法、头文件包含;
头文件:成员属性和成员函数的声明;
源文件:包含头文件;成员函数的定义,使用作用域限定符类名::成员函数名
指定成员函数所属的类作用域。
注:头文件中使用宏
#pragma once
或#ifndef
,可防止头文件被重复包含。
(2)一个类的成员属性是另一个类的对象(圆类的圆心是点类的对象);
(3)分别使用全局函数和成员函数【形参个数的不同】,判断点和圆的位置关系;
(4)函数形参使用引用替代变量,可避免数据拷贝,减少内存占用。
示例:
①点类头文件point.h
/* 头文件:成员属性和成员函数的声明 */
#pragma once //防止头文件被重复包含
#include <iostream>
using namespace std;
class Point {
private:
double X; //横坐标
double Y; //纵坐标
public:
/* 横坐标的设置与获取 */
void setX(double x);
double getX();
/* 纵坐标的设置与获取 */
void setY(double y);
double getY();
/* 两点的距离 */
//函数形参使用引用替代变量,可避免数据拷贝,减少内存占用
double getDistance(Point &p);
};
②点类源文件point.cpp
/* 源文件:成员函数的定义 */
//使用 作用域限定符 `类名::成员函数名` 指定成员函数所属的类作用域
#include "point.h"
#include <cmath> //数学方法
void Point::setX(double x) {
X = x;
}
double Point::getX() {
return X;
}
void Point::setY(double y) {
Y = y;
}
double Point::getY() {
return Y;
}
/* 成员函数:计算两点的距离 */
//函数形参使用引用替代变量,可避免数据拷贝,减少内存占用
double Point::getDistance(Point &p) {
return sqrt(pow(X - p.getX(), 2) + pow(Y - p.getY(), 2));
}
③圆类头文件circle.h
/* 头文件:成员属性和成员函数的声明 */
#pragma once //防止头文件被重复包含
#include <iostream>
using namespace std;
#include "point.h"
class Circle {
private:
double radius; //半径
Point center; //圆心
public:
/* 半径的设置与获取 */
void setRadius(double r);
double getRadius();
/* 圆心的设置与获取 */
void setCenter(Point p);
Point getCenter();
};
④圆类源文件circle.cpp
/* 源文件:成员函数的定义 */
//使用 作用域限定符 `类名::成员函数名` 指定成员函数所属的类作用域
#include "circle.h"
/* 半径的设置与获取 */
void Circle::setRadius(double r) {
radius = r;
};
double Circle::getRadius() {
return radius;
};
/* 圆心的设置与获取 */
void Circle::setCenter(Point p) {
center = p;
};
Point Circle::getCenter() {
return center;
};
⑤测试源文件main.cpp
#include <iostream>
using namespace std;
#include "point.h"
#include "circle.h"
/* 全局函数:计算两点的距离 */
//函数形参使用引用替代变量,可避免数据拷贝,减少内存占用
double g_getDistance(Circle &c, Point &p) {
return sqrt(pow(c.getCenter().getX() - p.getX(), 2)
+ pow(c.getCenter().getY() - p.getY(), 2));
}
/* 判断点与圆的位置关系 */
void isInCircle(double distance, double radius) {
if (distance < radius) {
cout << "点在圆内" << endl;
}
else if (distance == radius) {
cout << "点在圆上" << endl;
}
else if (distance > radius) {
cout << "点在圆外" << endl;
}
}
int main() {
/* 实例化圆类对象 */
Circle c;
c.setRadius(1); //设置半径
double r = c.getRadius();
//设置圆心
Point center;
center.setX(0);
center.setY(0);
c.setCenter(center);
/* 实例化点类对象 */
Point p;
p.setX(0);
p.setY(0.99); //点在圆内
/* 使用成员函数判断两点距离及位置关系 */
double d1 = p.getDistance(center);
cout << "点和圆心的距离:" << d1 << endl; //0.99
isInCircle(d1, r); //点在圆内
/* 使用全局函数判断两点距离及位置关系 */
double d2 = g_getDistance(c, p);
cout << "点和圆心的距离:" << d2 << endl; //0.99
isInCircle(d2, r); //点在圆内
return 0;
}