C++(5)封装、类和对象

封装 Encapsulation

可以将多个类型打包成一体,形成新的类型。

C语言的封装风格  数据放到一起打包 struct

然后把数据以引用或指针的方式传给行为

#include <iostream>

using namespace std;

struct Man
{
    string name;
    int age;
    char sex;
    float high;
    float salary;
};

struct Date
{
    int year;
    int month;
    int day;
};

//封装成函数
void init(Date d)
{
    cin>>d.year;
    cin>>d.month;
    cin>>d.day;
}

void print(Date & d)
{
    cout<<"year: "<<d.year<<" month: "<<d.month<<" day: "<<d.day<<endl;
}

bool isLeapYear(Date & d)
{
    if(d.year % 4 == 0 && d.year % 100 != 0 || d.year % 400 == 0)
        return true;
    else
        return false;
}

int main()
{
    Date d;  //定义变量,开辟空间
    init(d);
    print(d);

    if(isLeapYear(d))
        cout<<d.year<<" is leap year"<<endl;
    else:
        cout<<d.year<<" is not leap year"<<endl;

    return 0;
}

C++认为C语言封装不彻底

数据和行为分类,没有权限控制。对内数据开放,逻辑抽象。对外提供接口。

声明和实现要分开,使用类

#include <iostream>

using namespace std;

//权限控制 private protected public
//数据和行为在一起
//对内开放数据,逻辑抽象
//对外提供接口

class Date
{
public:
    void init()
    {
        cin>>year;
        cin>>month;
        cin>>day;
    }
    int getYear()
    {
        cout<<year<<endl;
    }
    void print()
    {
        cout<<"year:"<<"month:"<<"day:"<<endl;
        cout<<year<<":"<<month<<":"<<day<<endl;
    }
protected:
    int year;
    int month;
    int day;
};

int main()
{
    Date d;
    // d.year = 3000;

    d.print();

    return 0;
}
#include <iostream>

using namespace std;

class Date
{
public:
    void init();  // 类函数成员
    void print();
    int getYear();
    bool isLeapYear();
private:
    int year;  //数据成员 
    int month;
    int day;
}

void init()  //全局
{

}

class BB
{
public:
    void init();
}

void Date::init()
{
    cin>>year;
    cin>>month;
    cin>>day;
}

void BB::init()
{

}

int main()
{
    return 0;
}

类名其实也是一种变相的命名空间

举例:栈

stack.h

#ifndef STACK_H
#define STACK_H

class Stack
{
public:
    void init();
    bool isEmpty();
    bool isFull();
    char pop();
    void push(char c);
private:
    char space[1024];
    int top;
}

#endif // STACK_H

stack.cpp

#include "stack.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>

void Stack::init()
{
    top = 0;
    memset(space, 0, 1024);
}

bool Stack::isEmpty()
{
    return top == 0;
}

bool Stack::isFull()
{
    return top == 1024;
}

char Stack::pop()
{
    return space[--top];
}

void Stack::push(char c)
{
    space[top++] = c;
}

main.cpp

#include <iostream>
#include "stack.h"

using namespace std;

int main()
{
    Stack st;
    st.init();

    for(char v = 'a'; !st.isFull() && v != 'z'; v++)
    {
        st.push(v);
    }

    while(!st.isEmpty())
        cout<<st.pop()<<endl;

    return 0;
}

写在main.cpp一个文件中的

#include <iostream>
#include <stdlib.h>

using namespace std;

class Stack
{
public:
    void init();
    bool isEmpty();
    bool isFull();
    char pop();
    void push(char c);
private:
    char space[1024];
    int top;
};

void init(Stack & s)
{
    s.top = 0;
    memset(s.space, 0, 1024);
}

bool isEmpty(Stack & s)
{
    return s.top == 0;
}

bool isFull(Stack & s)
{
    return s.top == 1024;
}

char pop(Stack & s)
{
    return s.space[--s.top];
}

char push(Stack & s, char c)
{
    s.space[s.top++] = c;
}

int main()
{
    Stack st;
    init(st);

    if(!isFull())
        push(st, 'a');

    while(!isEmpty(st))
        cout<<pop(st)<<endl;

    return 0;
}

构造器、析构器

constructor 构造器

1、与类名相同,无返回值,被系统生成对象时自动调用,用于初始化

2、可以有参数,构造器的重载,默认参数。重载和默认不能同时存在

3、若未提供任何构造器,系统默认生成一个无参空构造器。若提供则不再生成默认构造器

#ifndef STACK_H
#define STACK_H

class Stack
{
public:
    Stack()  //无参构造
    {
        top = 0;
        space = new char[1000];
    }
    Stack(int size)  //有参构造
    {
        top = 0;
        space = new char[size];
        _size = size;
    }
    void init();
    bool isEmpty();
    bool isFull();
    char pop();
    void push(char c);

    ~Stack()
    {
        cout<<""<<endl;
    }

private:
    char space[1024];
    int top;
    int size;
}

#endif // STACK_H

destructor  析构器

1、~ 与类名相同,无参,无返回,对象消失时自动被调用。

2、用于对象销毁时的内存处理工作。

3、若未提供,系统置信生成一个空析构器。

举例:构建钟表

#include <iostream>
#include <time.h>
#include <iomanip>
#include <unistd.h>

using namespace std;

//初始化的数据来自系统,以后的逻辑运算及显示自实现

class Clock
{
public:
    Clock()
    {
        time_t t = time(NULL);
        struct tm ti = *localtime(&t);  //获得系统时间 struct tm *__cdecl localtime(const time_t * _Time)

        hour = ti.hour;
        min = ti.min;
        sec = ti.sec;
    }

    void run()
    {
        while(1)
        {
            show();  // 完成显示
            tick();  // 数据更新
        }
    }

private:
    void show()
    {
        system("clear");
        cout<<setw(2)<<setfill('0')<<hour<<":";
        cout<<setw(2)<<setfill('0')<<min<<":";
        cout<<setw(2)<<setfill('0')<<sec;
    }
    void tick()
    {
        sleep(1);
        if(++sec == 60)
        {
            sec = 0;
            if(++min == 60)
            {
                min = 0;
                if(hour == 24)
                {
                    hour = 0;
                }
            }
        }
    }

    int hour;
    int min;
    int sec;
};

int main()
{
    Clock c;
    c.run();
    return 0;    
}

Const修饰符

1、const修饰数据成员、成员函数、类对象

2、修饰数据成员时,初始化位置只能在参数列表中

被const修饰的数据成员不能被修改

3、修饰成员函数

位置:函数声明之后,函数实现体之前

意义:const函数承诺不会修改数据成员

能访问const 和非const数据成员,但不能修改非const数据成员

只能访问const成员函数。

构成重载

const对象只能调用const成员函数。

非const成员对象,优先调用非const成员函数,若无,则可调用const成员函数。

4、修饰类对象

const修饰函数,是从函数的层面,不修改数据。

const修饰对象,是从对象的层面,不修改数据,只能调用const成员函数。

#include <iostream>

using namespace std;

class A
{
public:
    A(int v)
        :val(v)
    {
    }
    
    void dis()
    {
        cout<<val<<endl;
    }
    void dis() const
    {
        cout<<"void dis() const"<<endl;
    }

private:
    const int val;
};

int main()
{
    A a;
    a.dis();

    return 0;
}

Static静态

全局变量  外延性 static  作用域:仅限于本文件  生命周期、存储位置

局部变量 auto

static 在类内部的表现,用来实现族类对象间的数据共享

在生成对象的时候,普通数据成员才有空间。而static成员在类声明的时候就已经开辟了空间(在data rw段)。

类本质也是一个命名空间

1、初始化  类内定义,类外初始化。type 类名::变量名 = 初始值

2、static 数据成员,既属于类,也属于对象,但终归属于类

3、static 修饰的成员函数,因为属于类,没有this指针,不能访问非static数据成员及成员函数

#include <iostream>

using namespace std;

//static 修饰成员函数,作用只用于管理static成员

class School
{
public:
    string & getTower()
    {
        return power;
    }
    static string & getLib()
    {
        return lib;
    }
private:
    string power;
    string lake;
    static string lib;
};

string School::lib = "aaaaa";  // 初始化静态数据成员,否则报错——C++无法解析的外部符号

int main()
{
    School::getLib() = "aa";
    School::getLib() += "bb";

    School cz, bn, blue;
    cz.getTower() = "aaa";
    bn,getTower() = "bbb";
    blue.getTower() = "ccc";

    cz.getLib() += "ddd";
    bn.getLib() += "eee";
    blue.getLib() += "fff";

    cout<<cz.getLib()<<endl;
    cout<<bn.getLib()<<endl;
    cout<<School::getLib()<<endl;

    return 0;
}
#include <iostream>

using namespace std;

class CCSprite
{
public:
    CCSprite(int d)
    {
        data = d;
        if(head == NULL)
        {
            this->next = NULL;
            head = this;
        }
        else
        {
            this->next = head->next;
            head = this;
        }
    }

    static void traverseCCSprite()
    {
        CCSprite * ph = head;
        while(ph != NULL)
        {
            cout<<ph->data<<endl;
            ph = ph->next;
        }
    }

private:
    int data;
    CCSprite * next;
    static CCSprite * head;
};

CCSprite * CCSprite::head = NULL;  //在外边初始化

int main()
{
    CCSprite a(1), b(2), c(3);
    for(int i = 100; i < 100; i++)
        new CCSprite(i);
    
    CCSprite::traverseCCSprite();
    return 0;
}

指向类成员

#include <iostream>
#include "string.h"

using namespace std;

class Stu
{
    Stu(string sn, int ia):
        name(sn), age(ia){}

    void print()
    {
        cout<<name<<"--"<<age<<endl;
    }

public:
    string name;
    int age;
};

int main()
{
    Stu s1("aaa", 39);
    Stu s2("bbb", 79);

    string Stu::* pn = &Stu::name;

    cout<<s1.name<<s2.name<<endl;
    cout<<s1.*pn<<s2.*pn<<endl;  // .* 

    return 0;
}
#include <iostream>

using namespace std;

class Widget
{
public:
    Widget()
    {
        pa[0] = &f;
        pa[1] = &g;
        pa[2] = &i;
        pa[3] = &j;
    }

    void select(int idx)
    {
        (this->*pa[idx])();
    }

private:
    void f() {cout<<"void f()"<<endl;}
    void g() {cout<<"void g()"<<endl;}
    void i() {cout<<"void i()"<<endl;}
    void j() {cout<<"void j()"<<endl;}

    enum {cnt = 4};
    void (Widget::*pa[cnt])() = {f, g, i, j};
};

//指向类成员函数的指针

int main()
{
    Widget w;
    w.select(0);

    return 0;
}

友元Friend    破坏了封装性

成员函数变友元函数

#include <iostream>
#include <math.h>

using namespace std;

class Point
{
public:
    Point(double xx, double yy)
    {
        x = xx;
        y = yy;
    }
    friend double getDistance(Point & a, Point & b);

private:
    double x, y;
};

double getDistance(Point & a, Point & b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx*dx + dy*dy);
}

int main()
{
    Point p1(1, 2);
    Point p2(3, 4);
    double dis = getDistance(p1, p2);
    cout<<dis<<endl;

    return 0;
}

增加PointManagement 管理类

#include <iostream>
#include <math.h>

using namespace std;

class Point;  //先声明类

class PointManagement
{
public:
    double getDirectDistance(Point & a, Point & b);  //两点间线段长度
    double getTriDistance(Point & a, Point & b);  //获得两点组成的三个边距离和
};

class Point
{
public:
    Point(double xx, double yy)
    {
        x = xx;
        y = yy;
    }
    friend double PointManagement::getDirectDistance(Point & a, Point & b);
    friend double PointManagement::getTriDistance(Point & a, Point & b);

private:
    double x, y;
};

double PointManagement::getDirectDistance(Point & a, Point & b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

double PointManagement::getTriDistance(Point & a, Point & b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    c1 = sqrt(dx * dx + dy * dy);
    return c1 + dx + dy;
}

int main()
{
    Point p1(1, 2);
    Point p2(3, 4);
    double dis = getDistance(p1, p2);
    cout<<dis<<endl;

    return 0;
}

友元类:把一个类作为另一个类的友元

把A声明为B的友元,就可以通过B的变量访问B的private数据成员。

class Point
{
public:
    Point(double xx, double yy)
    {
        x = xx;
        y = yy;
    }
    friend class PointManagement;  //友元类

private:
    double x, y;
};

class PointManagement
{
public:
    double getDirectDistance(Point & a, Point & b);  //两点间线段长度
    double getTriDistance(Point & a, Point & b);  //获得两点组成的三个边距离和
};

猜你喜欢

转载自blog.csdn.net/jiangyangll/article/details/132297446