C++ 类和对象(封装和对象的初始化和清理)

1.封装

1.1封装的意义

封装是C++面向对象三大特性之一。

意义:

1.将属性和行为作为一个整体,表现生活中的事物。

2.将属性和行为加以权限控制。

(类中的属性和行为统称成员,属性又叫成员属性,成员变量。行为又叫成员函数,成员方法)

意义1.

设计类时,将属性和行为写在一起,表现事物。

const double PI=3.14;
class Circle 
{
    //访问权限:公共权限 
    public:
    // 属性:半径
    int m_r; 
    //行为:获取半径 
    double zhouchang()
    {
        return 2 * PI * m_r;
    }
   
};

int main ()
{
    //实例化(通过一个类,创建一个对象的过程) 
    Circle cl;//这个圆就是具体的对象 
    cl.m_r =10;
    cout<<"圆的周长是: "<<cl.zhouchang() <<endl;
    return 0; 
}

意义2.

类在设计时,可以把属性和行为放在不同的权限下,加以控制。

访问权限有三种:

1.public         公共权限

2.protected   保护权限

3.private        私有权限

在类内,都可以访问,在类外,1.可以访问,2.3.不可以访问.(2.3.区别与继承有关,相对来说,3的控制力度最大)

1.2 struct与class的区别

struct默认权限是公共;

class默认权限是私有。

在class中,如果不写public等权限词,默认private,为私有。

2.对象的初始化和清理

像生活中电子产品的出厂设置,和销毁前清空数据的设置

2.1构造函数和析构函数

构造函数就是初始化,析构函数就是清理。这两个函数会被编译器自动调用,我们不写这俩函数,编译器也会提供。

构造函数:主要作用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。

析构函数:主要用于对象销毁前系统自动调用,执行前一些清理工作。

构造函数语法:类名(){}

1.没有返回值也不写void

2.函数名称与类名相同;

3.构造函数可以有函数,因此可以发生重载;

4.程序在调用对象时候会自动调用,无需手动调用而且只会调用一次。

析构函数语法:~类名(){}

1.没有返回值也不写void

2.函数名称与类名相同,在函数名称前加 ~;

3.构造函数不可以有函数,因此不可以发生重载;

4.程序在销毁对象时候会自动调用,无需手动调用而且只会调用一次。

class person
{
public:
    //1.构造函数 
    person()
    {
        cout<<"构造函数的调用"<<endl;
    }
    //2.析构函数
    ~person()
    {
        cout<<"person的析构函数"<<endl; 
     } 
};

2.2构造函数的分类及调用

两种分类方式:

按参数分:有参构造和无参构造

按类型分:普通构造和拷贝构造

三种调用方式:

括号法

显示法

隐式转换法 

#include<iostream>
#include<string>
using namespace std;

class person
{
public:
    //1.构造函数 
    person()//无参构造函数又叫默认构造函数 
    {
        cout<<"无参构造函数的调用"<<endl;
    }
    person(int a)
    {
        age=a;
        cout<<"有参构造函数"<<endl; 
    }
    person(const person &p)
    {
        age=p.age ;
        cout<<"拷贝构造"<<endl; 
    }  
    
    //2.析构函数
    ~person()
    {
        cout<<"person的析构函数"<<endl; 
     } 
     
     int age;
};

//构造和析构都是必须有的 实现,如果我们自己不提供,编译器会提供一个空实现的构造和析构 
void test01()
{
    //括号法 
    person p1;//默认构造函数调用
    person p2(10);//有参 构造函数调用
    person p3(p2);//拷贝构造函数调用
    //注意事项1:
    //调用默认构造函数时,不要加()
    //因为加()后,编译器会认为这是函数声明,不会认为在创建对象 
     

    //显示法 
    person p1;
    person p2=person(10);//有参构造
    person p3=person(p2);//拷贝构造
    
//    person(10);//匿名对象 特点:当前行执行结束后 ,系统会立即回收匿名对象; 
     
    //注意事项2;
    //不要利用拷贝构造函数来初始化匿名对象,编译器会认为这是声明对象,造成重定义 
    //person(p3);
    
     
    //隐式转换法 
    person p4=10;//相当于 person p4=person (10)  有参构造
    person p5=p4;//拷贝构造 person p5=person(p4)
}
 int main ()
 {
    test01();
    
    system("pause");
    return 0;   
 }

2.3拷贝构造函数调用时机

三种情况:

1.使用一个已经创建完毕的对象来初始化一个新对象 

2.值传递的方式给函数参数传值

3.值方式返回局部对象

class person
{
public:
    //1.构造函数 
    person()//无参构造函数又叫默认构造函数 
    {
        cout<<"person的默认构造函数调用"<<endl;
    }
    person(int a)
    {
        age=a;
        cout<<"person的有参构造函数"<<endl; 
    }
    person(const person &p)
    {
        age=p.age ;
        cout<<"penson的拷贝构造函数"<<endl; 
    }
    
    //2.析构函数
    ~person()
    {
        cout<<"person的析构函数"<<endl; 
     } 
     
     int age;
};

//使用一个已经创建完毕的对象来初始化一个新对象 
void test01()
{
    
    person p1(20);
    person p2(p1);
    
 } 

//值传递的方式给函数参数传值
void dowork(person p)
{
    
}

void test02()
{
    person p;
    dowork(p);
 } 
 
 //值方式返回局部对象
person dowork2()
{
     person p1;
     cout<<(int*)&p1<<endl;
     return p1;

void test03()
{
    person p=dowork2();
    cout<<(int*)&p<<endl;
}

2.4拷贝构造函数调用规则

1、默认情况下,创建一个类,编译器会给每一个类至少添加3个函数

默认构造(空实现:函数里没代码)

析构函数(空实现)

拷贝构造 (值拷贝)

2、如果我们写了有参构造函数,编译器就不再提供默认构造,依然提供拷贝构造。

如果我们写了拷贝构造函数,编译器也不会再提供其他普通构造函数。

2.5深拷贝与浅拷贝

class person
{
public:
    person(int age,int height)
    {
        m_age=age;
        m_height=new int(height);
        cout<<"有参构造函数" <<endl;
        
    }    
    person (const person &p)
    {
        cout <<"拷贝函数"<<endl;
        m_age=p.m_age ;
        //m_height=p.m_height ;编译器拷贝函数默认代码 
        //深拷贝操作
        m_height=new int(*p.m_height) ; 
    }
    ~person()
    {
        //析构函数里释放堆区数据 
        if(m_height!=NULL)
        {
            delete m_height;
            m_height=NULL;
        }
        cout <<"析构函数"<<endl; 
    }
    int m_age;
    int *m_height;
};

void test()
{
    person p1(18,180);

    cout << "年龄 : "<<p1.m_age <<" 身高 : "<<*p1.m_height <<endl; 
    
    person p2(p1);

    cout << "年龄 : "<<p2.m_age <<" 身高 : "<<*p2.m_height <<endl;     
}

当用编译器提供的拷贝函数时,就是浅拷贝。如上有参构造函数中,m_height 是用new在堆区开辟的数据.需要在析构函数里手动释放m_height;如果用浅拷贝,p1执行完后会用析构函数释放m_height。后面拷贝函数p2执行完后会再次释放m_height。造成重复释放,出现错误。

这时需要深拷贝,开辟一个新的new数据,这样p2释放new数据时,不会重复释放。

2.6初始化列表

语法:构造函数 ():属性1(值1),属性2(值2)...{}

class person
{
public:
    //传统初始化操作 
//    person(int a,int b,int c)
//    {
//        m_a=a;
//        m_b=b;
//        m_c=c;
//    }
//    
    //初始化列表初始化属性
    person(int a,int b,int c):m_a(a),m_b(b),m_c(c)
    {
        
    } 
     
    int m_a;
    int m_b;
    int m_c;
};

void test01()
{

    person p(30,20,10);
    cout << "m_a= "<< p.m_a  <<endl;
    cout << "m_b= "<< p.m_b  <<endl;
    cout << "m_c= "<< p.m_c  <<endl;
    
}
  

2.7类对象作为类的成员

c++中类的成员可以是另一个类的对象,称为对象成员

class  A  {}

class  B 

{

         A   a;

B类中有对象A作为成员,A称为对象成员.

2.8静态成员

静态成员就是在成员函数和成员变量前面加入static关键字,称为静态成员

静态成员分为:

静态成员变量:

1.所有对象共享同一份数据

2.在编译阶段分配内存

3.类内声明,类外初始化

静态成员函数:

1.所有对象共享同一函数

2.静态成员函数只能访问静态成员变量

class person
{
    public:
        //静态成员函数 
        static void fun()
        {
            m_A=100;//静态变量被共享 
            m_B=200;//静态成员函数只能访问静态成员变量,所以函数里加上m_B会报错 
            //因为无法区分m_B是那个对象的m_B 
            cout <<"static void fun 调用"<<endl;
        }
        
        static int m_A;//静态成员变量 (必须在类内声明,再在类外初始化一下 )
        int m_B;//非静态成员变量 
        
} ;

    int person::m_A =0; 
//所有对象共享同一个函数 
//两种访问方式 
void test1()
{
    //1.通过对象访问
    person p;
    p.fun() ;
    //2.通过类名访问
    person :: fun() 
}

注意:如果在私有权限里声明静态成员函数则在类外无法访问

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值