c++基础之封装上

来源:互联网 发布:淘宝身份证认证照片 编辑:程序博客网 时间:2024/06/06 00:41

类的三大特性:封装,继承和多态


一、类和对象的定义

#include <iostream>using namespace std;class Coordinate{public:    int x;    int y;    void printX()    {        cout<<x<<endl;    }    void printY()    {        cout<<y<<endl;    }};int main(){    Coordinate c1;    c1.x=1;    c1.y=2;    c1.printX();    c1.printY();    Coordinate *p=new Coordinate();    p->x=3;    p->y=4;    p->printX();    p->printY();    delete p;    return 0;}

运行结果:

1

2

3

4


二、类的封装

1.面向对象的指导思想

    封装是面向对象的三大特征之一,就是将类的状态信息隐藏在类的内部,不允许外部程序直接访问,而通过该类提供的方法来实现对隐藏信息的操作和访问。在代码层次上就是将所有的数据操作转化为对成员函数的调用,即对象在程序的所有行为都通过成员函数来完成。

2.封装的好处

(1)让使用者只能通过程序规定的方法来访问数据;可以方便的加入存取控制语句,限制不合理操作;

(2)隐藏类的实现细节

(3)便于维护,增强了代码的可维护性

(4)例子:

#include <iostream>using namespace std;class Student{public:    void setAge(int _age)    {        if(_age>0&&_age<100)         age=_age;        else         age=0;    }    int getAge()    {        return age;    }    void setName(string _name)    {        name=_name;    }    string getName()    {        return name;    }private:  string name;  int age;};int main(){    Student s1;    s1.setAge(10);    s1.setName("zhangsan");    cout<<s1.getAge()<<" "<<s1.getName()<<endl;    return 0;}

3.类外定义

   即成员函数的声明和实现是分开的。

  (1)同文件类外定义

#include <iostream>using namespace std;class Student{public:    Student();//无参构造函数    Student(string _name,int _age);    void setAge(int _age);    int getAge();    void setName(string _name);    string getName();private:  string name;  int age;};Student::Student(){}Student::Student(string _name,int _age){}void Student::setAge(int _age){}int Student::getAge(){}void Student::setName(string _name){}string Student::getName(){}int main(){ //  ......    return 0;}

  (2)不同文件类外定义

      ♦声明在.h文件中;

#include <iostream>using namespace std;class Student{public:    Student();//无参构造函数    Student(string _name,int _age);    void setAge(int _age);    int getAge();    void setName(string _name);    string getName();private:  string name;  int age;};

   ♦实现在.cpp文件中。

#include "Studnet.h"Student::Student(){}Student::Student(string _name,int _age){}void Student::setAge(int _age){}int Student::getAge(){}void Student::setName(string _name){}string Student::getName(){}
   ♦使用在main.cpp中
#include "Student.h"#include <iostream>using namespace std;int main(){ //  ......    return 0;}

三、对象的结构

1.内存按照用途分为5个区

(1)栈区:内存由系统分配和回收,程序员无需关心。

      int x=0;int *p=NULL:

(2)堆区:分配内存由new分配,释放由delete释放。

(3)全局区:存储全局变量和静态变量。

(4)常量区:存储字符串和常量。

(5)代码区:存储逻辑代码的二进制

2.对象中数据是如何存储的。

   类在实例化之前是不会占用堆或栈的内存的,但在实例化之后,每个对象都会在栈中开辟内存,占据不同的内存。逻辑代码却只有一份,放在代码区。所有的对象共享逻辑代码。

四、对象的初始化 

1.初始化函数

class Student{public:    void init()    {        name="";        age=0;    }    void setAge(int _age);    int getAge();    void setName(string _name);    string getName();private:  string name;  int age;};
但是有缺点,比如忘记调用或者重复调用初始化函数,所以产生了构造函数。

2.构造函数

(1)分为无参构造函数和有参构造函数

(2)特点

  ①在对象实例化时自动调用,而且可以重载。

  ②实例化时只会调用一个构造函数

  ③当用户没有定义构造函数时,编译器自动生成一个构造函数。

(3)例子

#include <iostream>using namespace std;class Student{public:    Student()//无参构造函数    {        name="li";        age=0;    }    Student(string _name,int _age)//有参构造函数    {        name=_name;        age=_age;    }   void setAge(int _age)    {        if(_age>0&&_age<100)         age=_age;        else         age=0;    }    int getAge()    {        return age;    }    void setName(string _name)    {        name=_name;    }    string getName()    {        return name;    }private:  string name;  int age;};int main(){    Student s1;    Student s2("zhang",10);    cout<<s1.getName()<<" "<<s1.getAge()<<endl;    cout<<s2.getName()<<" "<<s2.getAge()<<endl;    return 0;}
运行结果:


3.构造函数初始化列表

  (1)例子

    

#include <iostream>using namespace std;class Student{public:    Student():name("li"),age(0){};    Student(string _name,int _age):name(_name),age(_age){};   void setAge(int _age)    {        if(_age>0&&_age<100)         age=_age;        else         age=0;    }    int getAge()    {        return age;    }    void setName(string _name)    {        name=_name;    }    string getName()    {        return name;    }private:  string name;  int age;};int main(){    Student s1;    Student s2("zhang",10);    cout<<s1.getName()<<" "<<s1.getAge()<<endl;    cout<<s2.getName()<<" "<<s2.getAge()<<endl;    return 0;}
(2)特点

   ①初始化列表先于构造函数执行,编译器先给初始化列表的数据成员赋值,再执行构造函数中的代码

   ②初始化列表只能用于构造函数

   ③效率高且速度快

(3)初始化列表的必要性(不可取代的地位)

    ♦错误的代码:

class Circle{  public:      Circle()      {           PI=3.14;      }  private:    const double PI;};
    ♦正确的代码

class Circle{  public:      Circle():PI(3.14){}  private:    const double PI;};

五、拷贝构造函数

1.浅拷贝

只是将数据成员的值进行copy

#include<iostream>using namespace std;class Array{public:    Array()    {        m_iCount=5;        arr=new int[m_iCount];         cout<<"Array()"<<endl;    }    Array(const Array& a1)    {        cout<<"Array&"<<endl;        m_iCount=a1.m_iCount;        arr=a1.arr;    }    ~Array()    {        m_iCount=0;        delete []arr;        cout<<"~Array()"<<endl;    }    void printAddr()    {        cout<<arr<<endl;    }private:    int m_iCount;    int *arr;};int main(){    Array a1;    Array a2=a1;    a1.printAddr();    a2.printAddr();    return 0;}
运行结果:

运行结果:


地址指向相同的内存。

存在问题:

♦两个对象的arr指向的是同一块地址,如果对a2的arr重新赋值,则a1的arr也会变。

♦销毁对象的时候销毁了两次,即同一块内存被释放了两次。

2.深拷贝

copy时不是简单地copy地址,而是将里面的内容copy过来

#include<iostream>using namespace std;class Array{public:    Array()    {        m_iCount=5;        arr=new int[m_iCount];         cout<<"Array()"<<endl;    }    Array(const Array& a1)    {        cout<<"Array&"<<endl;        m_iCount=a1.m_iCount;        arr=new int[m_iCount];        for(int i=0;i<m_iCount;i++)            arr[i]=a1.arr[i];    }    ~Array()    {        m_iCount=0;        delete []arr;        cout<<"~Array()"<<endl;    }    void printAddr()    {        cout<<arr<<endl;    }private:    int m_iCount;    int *arr;};int main(){    Array a1;    Array a2=a1;    a1.printAddr();    a2.printAddr();    return 0;}

运行结果:


地址指向不同的内存。


六、析构函数

1.对象销毁时自动调用,回收资源,收拾残局。

  如果没有自定义析构函数,系统也会自动生成一个析构函数。

2.例子

#include <iostream>using namespace std;class Student{public :    Student()    {        cout<<"Studnet"<<endl;    }    ~Student()    {        cout<<"~Student"<<endl;    }private:    string name;};int main(){    Student s1;    return 0;}

运行结果:


3.析构函数存在的必要

如果定义的是指针,可以销毁堆内存。

#include <iostream>using namespace std;class Student{public :    Student()    {        name=new char[20];        cout<<"Studnet"<<endl;    }    ~Student()    {        delete []name;        cout<<"~Student"<<endl;    }private:    char *name;};int main(){    Student s1;    return 0;}
运行结果:



0 0