面向对象的程序设计方法
类的定义
class 类名
{
访问范围说明符:
成员变量1
成员变量2
…
成员函数声明1
成员函数声明2
访问范围说明符:
更多成员变量
更多成员函数声明
…
};
从客观事物抽象出来的例子
例: 客观事物->类
写一个程序, 输入矩形的宽和高, 输出面积和周长。
- 矩形的属性-宽和高
- 两个变量,分别代表宽和高
- 对矩形的操作
- 设置宽和高
- 计算面积
- 计算周长
class CRectangle {
public:
int w, h;
void Init( int w_, int h_ ) {
w = w_; h = h_;
}
int Area() {
return w * h;
}
int Perimeter() {
return 2 * ( w + h );
}
}; //必须有分号
int main() {
int w, h;
CRectangle r; //r是一个对象
cin >> w >> h;
r.Init(w, h);
cout << r.Area() << endl << r. Perimeter();
return 0;
}
类定义的变量 ->类的实例 -> “对象”
对象的内存分配
- 对象的内存空间
- 对象的大小 = 所有成员变量的大小之和
- E.g.
CRectangle
类的对象,sizeof(CRectangle)=8
- 每个对象各有自己的储存空间
- 一个对象的某个成员变量被改变,不会影响到其他的对象
对象间的运算
- 对象之间可以用
=
进行赋值 - 不能用
== != > < >= <=
进行比较
- 除非这些运算符经过了重载
访问类的成员变量和成员函数
- 用法1:对象名.成员名
CRectangle r1, r2;
r1.w = 5;
r2.Init(3,4);
- 用法2:指针->成员名
CRectangle r1, r2;
CRectangle * p1 = & r1;
CRectangle * p2 = & r2;
p1->w = 5;
p2->Init(3,4); //Init作用在p2指向的对象上
- 用法3:引用名.成员名
CRectangle r2;
CRectangle & rr = r2;
rr.w = 5;
rr.Init(3,4); //rr的值变了,r2的值也变
另一种输出结果的方式
void PrintRectangle(CRectangle & r) {
cout << r.Area() << ","<< r.Perimeter();
}
CRectangle r3;
r3.Init(3,4);
PrintRectangle(r3);
类的成员函数的另一种方法
成员函数体和类的定义分开写:
class CRectangle
{
public:
int w, h;
int Area(); //成员函数仅在此处声明
int Perimeter() ;
void Init( int w_, int h_ );
};
int CRectangle::Area() {
return w * h;
}
int CRectangle::Perimeter() {
return 2 * ( w + h );
}
void CRectangle::Init( int w_, int h_ ) {
w = w_; h = h_;
}
类成员的可访问范围
- 关键字– 类成员可被访问的范围
private
:指定私有成员, 只能在成员函数内被访问public
:指定公有成员, 可以在任何地方被访问private
:指定保护成员
- 三种关键字出现的次数和先后次序都没有限制
class className {
private:
私有属性和函数
public:
公有属性和函数
protected:
保护属性和函数
};
缺省为私有成员
class Man {
int nAge; //私有成员
char szName[20]; // 私有成员
public:
void SetName(char * Name){
strcpy(szName, Name);
}
};
- 类的成员函数内部, 可以访问:
- 当前对象的全部属性, 函数
- 同类其它对象的全部属性, 函数
类的成员函数以外的地方,
- 只能够访问该类对象的公有成员
设置私有成员的目的
- 强制对成员变量的访问一定要通过成员函数进行
- 设置私有成员的机制 – 隐藏
内联成员函数和重载成员函数
内联成员函数
inline
+ 成员函数- 整个函数体出现在类定义内部
class B{
inline void func1(); // 1
void func2() { // 2
};
};
void B::func1() { }
成员函数的重载及参数缺省
- 重载成员函数
- 成员函数–带缺省参数
#include <iostream>
using namespace std;
class Location {
private :
int x, y;
public:
void init( int x=0 , int y = 0 );
void valueX( int val ) { x = val ; }
int valueX() { return x; }
};
void Location::init( int X, int Y){
x = X;
y = Y;
}
int main() {
Location A;
A.init(5);
A.valueX(5);
cout << A.valueX(); // 输出:5
return 0;
}
- 使用缺省参数要注意避免有函数重载时的二义性
class Location {
private:
int x, y;
public:
void init( int x =0, int y = 0 );
void valueX( int val = 0 ) { x = val; }
int valueX() { return x; }
};
Location A;
A.valueX(); //错误, 编译器无法判断调用哪个valueX
构造函数
基本概念
成员函数的一种
- 名字与类名相同,可以有参数,不能有返回值(void也不行)
- 作用是对对象进行初始化,如给成员变量赋初值
- 如果定义类时没写构造函数,则编译器生成一个默认的无参数 的构造函数
- 默认构造函数无参数,不做任何操作
- 如果定义了构造函数,则编译器
- 对象生成时构造函数自动被调用。对象一旦生成,就再也不能在 其上执行构造函数
- 一个类可以有多个构造函数
为什么需要构造函数:
- 构造函数执行必要的初始化工作,有了构造函数,就不必专门再写初始化函数,也不用担心忘记调用初始化函数。
- 有时对象没被初始化就使用,会导致程序出错。
class Complex {
private :
double real, imag;
public:
void Set( double r, double i);
}; //编译器自动生成默认构造函数
Complex c1; //默认构造函数被调用
Complex * pc = new Complex; //默认构造函数被调用
class Complex {
private :
double real, imag;
public:
Complex( double r, double i = 0);
};
Complex::Complex( double r, double i) { // 在实现时不再写出默认值
real = r; imag = i;
}
Complex c1; // error, 缺少构造函数的参数
Complex * pc = new Complex; // error, 没有参数
Complex c1(2); // OK
Complex c1(2,4), c2(3,5); Complex * pc = new Complex(3,4);
可以有多个构造函数,参数个数或类型不同。
class Complex {
private :
double real, imag;
public:
void Set( double r, double i );
Complex(double r, double i );
Complex (double r );
Complex (Complex c1, Complex c2);
};
Complex::Complex(double r, double i) {
real = r; imag = i;
}
Complex::Complex(double r) {
real = r; imag = 0;
}
Complex::Complex (Complex c1, Complex c2) {
real = c1.real+c2.real;
imag = c1.imag+c2.imag;
}
Complex c1(3) , c2 (1,0), c3(c1,c2);
// c1 = {3, 0}, c2 = {1, 0}, c3 = {4, 0};
构造函数最好是public的,private构造函数不能直接用来初始化对象。
构造函数在数组中的使用
class CSample {
int x;
public:
CSample() {
cout << "Constructor 1 Called" << endl;
}
CSample(int n) {
x = n; cout << "Constructor 2 Called" << endl;
}
};
int main() {
CSample array1[2];
cout << "step1"<<endl;
CSample array2[2] = {4,5};
cout << "step2"<<endl;
CSample array3[2] = {3};
cout << "step3"<<endl;
CSample * array4 =
new CSample[2];
delete []array4;
return 0;
}
输出:
Constructor 1 Called
Constructor 1 Called
step1
Constructor 2 Called
Constructor 2 Called
step2
Constructor 2 Called
Constructor 1 Called
step3
Constructor 1 Called
Constructor 1 Called
class Test {
public:
Test( int n) { } //(1)
Test( int n, int m) { } //(2)
Test() { } //(3)
};
Test array1[3] = { 1, Test(1,2) }; // 三个元素分别用(1),(2),(3)初始化
Test array2[3] = { Test(2,3), Test(1,2) , 1}; // 三个元素分别用(2),(2),(1)初始化
Test * pArray[3] = { new Test(4), new Test(1,2) }; //两个元素分别用(1),(2) 初始化