C++之类与封装

类(class)

C++与C最大的一个区别就是,比C语言要多很多面向对象的特性,而对象的体现很多都是在类上。C语言中会把很多功能封装在一个函数中,而在C++中多了一个概念也就是类,虽然面向对象的执行效率不高,但是代码会比较整齐。要对面向对象有深入了解可以先从类下手。

如何定义一个类
class p{
	/*代码体*/
};

类和结构体定义会比较类似,但是它们也是有区别的,首先是他们的访问默认权限,在类中如果不声明权限,那么默认是private私有的,结构体默认访问权限是public公有的,然后在C++中有规定,任何不同的对象不能拥有相同的内存地址,对于空类或空结构体他们的大小都为1。

封装

封装顾名思义就是把类中的成员遮蔽起来,不能让外界直接访问类中的成员,只能通过类中留下的访问接口,来访问或者修改类中的成员,这样的好处就是安全,能够最大限度的保证你的内部数据不会被外界轻易的修改,C++有这三种关键字来修饰访问权限,public、protected、private,外界对类访问的权限逐渐降低,所以尽量把类中的成员变量都用private修饰。

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

class person{
        public:
                void getName(){
                        cout<<"name is"<<m_name<<endl;
                }
                void setName(string name){
                        m_name=name;
                }
        private:
                int m_age;
                string m_name;
};
int main(){
        person p1;
        p1.setName("张三");
        p1.getName();
       非法调用// cout<<p1.m_name<<endl;
        return 0;
}

例一

这里简单的实现一个封装,使实例的对象无法直接访问成员变量,否则会出错

构造函数

我们除了给变量初始化除了通过实例化对象赋值,还可以用其他方法赋值吗,当然是可以的,这里就用到了C++类中的构造函数,构造函数是怎么样一个结构呢,他是一个名字和类名相同,但是不需要加任何返回值类型的函数。

举例有一个类class p{
	构造函数:p(){

		}
};

既然是函数那肯定可以跟上参数的,当带上参数时,它就是带参构造函数,当程序员不在类中定义构造函数时,会默认生成一个无参的构造函数,构造函数可以根据自己的实际需求来写。

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

class person{
        public:
                person(){
              		  cout<<"这是无参构造方法"<<endl;
                }
                person(string name){
                	cout<<"这是带参构造方法"<<endl;
                        m_name=name;
                }
                void getName(){
                        cout<<m_name<<endl;
                }
        private:
                int m_age;
                string m_name;
};
int main(){
        person p1("张三");
        p1.getName();
        person p2;
        return 0;
}

请添加图片描述
这里可以看到,带参构造函数和无参构造函数是可以同时存在于类中的,调用取决于在实例化对象时是否传递了参数,这里需要注意当调用无参构造函数时,不需要加(),否则会被编译器当成普通函数的声明,除了直接在括号内像普通函数一样传参,还可以用一种方法传参,它就是初始化列表,顾名思义就是用来做初始化用的。如下

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

class person{
        public:
                person(string name,int age):m_name(name),m_age(age){
                cout<<"这是带参构造方法"<<endl;
                }
                void getName(){
                        cout<<m_name<<"的岁数是:"<<m_age<<endl;
                }
        private:
                int m_age;
                string m_name;
};
int main(){
        person p1("张三",36);
        p1.getName();
        person p2;
        return 0;
}

请添加图片描述

析构函数

除了默认有构造函数外还会有一个析构函数,析构函数是在某个实例化对象结束运行之后,用来释放空间用的,并且不可以有参数,不可以发生重载。

格式是类person{ 
		析构函数:~person(){

	}

}

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

class person{
        public:
                person(){

                cout<<"这是无参构造方法"<<endl;
                }
                person(string name,int age):m_name(name),m_age(age){
                cout<<"这是带参构造方法"<<endl;

                }

                ~person(){
                cout<<"这是析构函数"<<endl;
                }
                void getName(){
                        cout<<m_name<<"的岁数是:"<<m_age<<endl;
                }
        private:
                int m_age;
                string m_name;
};


int main(){
        person p1("张三",36);
        p1.getName();
        person p2(p1);
        p2.getName();
        return 0;
}

请添加图片描述
可以看到析构函数都是最后才运行,所以作用就是用来释放对象的内存空间的

拷贝构造函数

除了默认有一个无参构造函数外,第三个会有一个默认的拷贝构造函数,它的作用是当实例化好一个一个对象后,把这个对象当作参数传递给拷贝构造函数,被拷贝的对象会把所有对象成员赋值一遍给目的对象。

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

class person{
        public:
                person(){

                cout<<"这是无参构造方法"<<endl;
                }
                person(string name,int age):m_name(name),m_age(age){
                cout<<"这是带参构造方法"<<endl;

                }
                /*person(const person &p){
                        cout<<"这是拷贝构造函数"<<endl;
                        m_name=p.m_name;
                        m_age=20;
                }*/
                void getName(){
                        cout<<m_name<<"的岁数是:"<<m_age<<endl;
                }
        private:
                int m_age;
                string m_name;
};
int main(){
        person p1("张三",36);
        p1.getName();
        person p2(p1);
        p2.getName();
        return 0;
}

默认拷贝构造函数会全部拷贝,所以也可以自己写拷贝构造函数,如上

注释掉后

请添加图片描述

未注释

请添加图片描述
注意这里拷贝构造函数的参数是引用,而且必须加上const修饰

浅拷贝与深拷贝

浅拷贝是指拷贝函数直接在数值上直接拷贝,没有用到指针类型的参数,可以用到浅拷贝,若是用到了指针类型的,就可以用深拷贝,来重新申请一段空间,因为用到了指针类型的参数必定会遇到空间创建与释放的操作,那么如果只用了浅拷贝就会导致内存重复释放的危险。

浅拷贝(重复释放导致段错误)
#include <iostream>
#include <string>
using namespace std;

class person{
        public:
                person(){

                cout<<"这是无参构造方法"<<endl;
                }
                person(string name,int age){
                cout<<"这是带参构造方法"<<endl;
                        m_age=new int(age);

                }
				  ~person(){
                        if(m_age!=NULL){
                                delete m_age;
                                m_age=NULL;
	                       }
                cout<<"这是析构函数"<<endl;
                }
                person(const person &p){
                        cout<<"这是拷贝构造函数"<<endl;
                        m_name=p.m_name;
                		m_age=p.m_age;默认拷贝构造函数的做法
                //        m_age=new int (*p.m_age);
                }
                void getName(){
                        cout<<m_name<<"的岁数是:"<<*m_age<<endl;
                }
        private:
                int *m_age;
                string m_name;
};
int main(){
        person p1("张三",36);
        p1.getName();
        person p2(p1);
        p2.getName();
        return 0;

请添加图片描述

深拷贝
#include <iostream>
#include <string>
using namespace std;

class person{
        public:
                person(){

                cout<<"这是无参构造方法"<<endl;
                }
                person(string name,int age){
                cout<<"这是带参构造方法"<<endl;
                        m_age=new int(age);

                }
				  ~person(){
                        if(m_age!=NULL){
                                delete m_age;
                                m_age=NULL;
	                       }
                cout<<"这是析构函数"<<endl;
                }
                person(const person &p){
                        cout<<"这是拷贝构造函数"<<endl;
                        m_name=p.m_name;
                //		m_age=p.m_age;默认拷贝构造函数的做法
                        m_age=new int (*p.m_age);
                }
                void getName(){
                        cout<<m_name<<"的岁数是:"<<*m_age<<endl;
                }
        private:
                int *m_age;
                string m_name;
};
int main(){
        person p1("张三",36);
        p1.getName();
        person p2(p1);
        p2.getName();
        return 0;

请添加图片描述
这里可以思考一个问题,当一个类里有另一个类作为成员时,那么各自的构造函数和析构函数是谁先运行,谁后运行呢?我们可以实践一下。

#include <iostream>
using namespace std;
 class student{
        public:
                student(){
                        cout<<"这是类1的构造函数"<<endl;
                }
                ~student(){
                        cout<<"这是类1的析构函数"<<endl;
                }
};
class person{
        public:
                person(){
                        cout<<"这是类2的构造函数"<<endl;
                }
                ~person(){
                        cout<<"这是类2的析构函数"<<endl;
                }
        student s1;
};
int main(){
        person p1;
        return 0;
}

请添加图片描述
这里可以看到先运行被调用的类的构造函数,然后是本类的构造函数,然后是本类的析构函数,然后才是被调用的类的析构函数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值