《程序设计实习》之【类和对象初探】

面向对象的程序设计方法



类的定义

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) 初始化

猜你喜欢

转载自blog.csdn.net/beashaper_/article/details/80555932