栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++笔记(六)之核心编程(四)(二)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++笔记(六)之核心编程(四)(二)

四.类和对象

2.对象的初始化和清理
  • 电脑、手机等电子产品基本都有“出厂设置”,我们可以删除一些隐私数据以保安全
  • C++的面向对象来自生活,每个对象也都有初始设置和对象销毁的清理数据选项
一.构造函数和析构函数 1.概念
  • 构造函数:创建对象时为对象的成员属性赋值(也就是初始化程序),编译器自动调用
  • 析构函数:对象撤销前系统自动调用,执行一些清理工作
  • 构造函数和析构函数是完成对象初始化和清理工作的(编译器会自动调用),如果编程中不提供这两个函数的话,编译器会自动提供,但是编译器提供的是空的。
2.构造函数的语法:类名(){}
  • 构造函数没有返回值也不用写void
  • 函数名与类名相同
  • 构造函数可以有参数,因此可以发生重载
  • 程序在调用对象时会自动调用构造函数,无须手动调用,而且只会调用一次
  • #include
    using namespace std;
    
    class person
    {
    public:
    //构造函数 类名(){}
    	person()//无须加viod、可以有参数也可以无参数,函数名和类名是相同的(都是person)
    	{
    		cout << "构造函数的调用" << endl;//你不写这个的话,编译器也会给你写,
    		                                 //只不过,编译器写的是空的,也就是一个黑屏,什么也没有的
    		                                 //而你写了,屏幕上就显示你写的东西
    	}
    };
    
    void test01()
    {
    	person p;
    }
    int main()
    {
    	test01();//屏幕上值出现一次,说明了值调用一次构造函数
    	system("pause");
    	return 0;
    }

3.析构函数语法:类名(){}
  • 构造函数没有返回值也不用写void
  • 函数名与类名相同,在名称前加上符号 ~
  • 构造函数可以没有参数,因此不可以发生重载
  • 程序在调用对象时会自动调用构造函数,无须手动调用,而且只会调用一次
  • #include
    using namespace std;
    
    //构造函数
    class person
    {
    public:
    	person()//无须加viod、可以有参数也可以无参数
    	{
    		cout << "构造函数的调用" << endl;//你不写这个的话,编译器也会给你写,
    		                                 //只不过,编译器写的是空的,也就是一个黑屏,什么也没有的
    		                                 //而你写了,屏幕上就显示你写的东西
    	}
    	//析构函数:~类名(){}
    	~person()//无须加viod、不可以有参数
    	{
    		cout << "析构函数的调用" << endl;
    	}
    };
    
    void test01()
    {
    	person p;//在栈上,test01执行完成后,释放这个对象
    }
    int main()
    {
    	test01();//屏幕上值出现一次,说明了值调用一次构造函数
    	system("pause");
    	return 0;
    }

二.构造函数的分类及调用 1.两种分类
  • 按参数分类:有参数和无参数(默认构造)
  • 按类型分类:普通构造和拷贝构造(也就是复制的意思)
2.三种调用函数 
  • 括号发
  • 显示法
  • 隐式转换法
3.注意:
  • 调用默认构造函数的时候,不要加括号(因为编译器会认为这样写是函数的声明)

  • 不要利用拷贝函数来初始化匿名对象

  • #include
    using namespace std;
    
    
    class person
    {
    public:
    	//构造函数
    	person()
    	{
    		cout << "构造无参函数的调用" << endl;
    	}
    	person(int a)
    	{
    		age = a;
    		cout << "构造有参函数的调用" << endl;
    	}
    	//拷贝构造函数
    	person(const person &p)//要用引用常量的方式拷贝
    	{
    		age = p.age;//将传入的人的所有的属性拷贝到当前对象的身上
    		cout << "拷贝构造函数的调用" << endl;
    	}
    	~person()
    	{
    		cout << "析构函数的调用" << endl;
    	}
    	int age;
    };
    
    //调用
    void test01()
    {
    	//括号法
    	cout << "括号法调用:" << endl;
    	person p1;//默认函数构造调用
    	person p2(10);//有参函数的调用
    	person p3(p2);//拷贝函数的调用
    
    	cout << "p2的年龄:" << p2.age << endl;//上边传入了10,所以p2的年龄是10
    	cout << "p3的年龄:" << p3.age << endl;//将p2的年龄拷贝入了p3,所以p3也是10
    
    	//显示法
    	cout << "显示法调用:" << endl;
    	person p4;//默认构造
    	person p5 = person(10);//有参函数调用
    	person p6 = person(p5);//拷贝函数调用
    
    	person(10);//匿名对象   特点:当前行执行完之后,系统会立即回收掉匿名对象
    	cout << "aaa" << endl;//匿名对象先被释放后再来执行这个输出
    	     //拷贝函数初始化匿名对象
    	//person(p5);//编译器认为person(p5)=person p5,编译器会报错
    	
    	cout << "隐式转换法" << endl;
    	//隐式转换法
    	person p7 = 10;//相当于person p7 =person (10)    有参构造
    	person p8 = p7;//拷贝构造
    }
    int main()
    {
    	test01();
    	system("pause");
    	return 0; 
    }

三.拷贝函数的调用时机 用到的情况
  • 使用一个已经创建完毕的对象来初始化一个新的对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象
#include
using namespace std;


class person
{
public:
	person()
	{
		cout << "默认构造函数的调用" << endl;
	}
	person(int age)//初始化age
	{
		cout << "有参构造函数的调用" << endl;
		m_age = age;
	}
	person(const person &p)//拷贝函数
	{
		cout << "拷贝函数的调用" << endl;
		m_age = p.m_age;
	}
	~person()
	{
		cout << "析构函数的调用" << endl;
	}
	int m_age;
};

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

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

}

void test02()
{
	person p;
	dowork(p);
}

//值方式返回局部对象
person dowork03()
{
	person p3;//调用默认函数
	cout << (int*)&p3 << endl;
	return p3;//调用拷贝函数
	//根据p3拷贝一个新的对象,返回
}
void test03()
{
	person p = dowork03();
	cout << (int*)&p << endl;
}
int main()
{
	cout << "01" << endl;
	test01();
	cout << "02" << endl;
	test02();
	cout << "03" << endl;
	test03();
	system("pause");
	return 0; 
}

四.构造函数调用规则 1.默认情况 ,c++编程至少给一个类添加三个函数
  • 默认构造函数(无参  函数体为空)
  • 默认析构函数(无参  函数体为空)
  • 默认拷贝函数,对对象属性进行拷贝
2.构造函数调用规则
  • 如果用户定义有参构造函数,c++不在默认无参构造函数,但是提高无参析构函数
  • 如果用户定义拷贝构造函数,c++不在提供任何其他构造函数
五.深拷贝和浅拷贝
  • 浅拷贝:简单的赋值拷贝操作
  • 深拷贝:在堆区重新申请空间,进行拷贝操作
  • 总结:如果属性有在堆区开辟的,一定要自己提供拷贝函数,防止浅拷贝带来的问题

1.浅拷贝问题:堆区重复释放

#include
using namespace std;


class person
{
public:
	person()
	{
		cout << "默认构造函数的调用" << endl;
	}
	person(int age,int height)//初始化age
	{
		cout << "有参构造函数的调用" << endl;
		m_age = age;
		m_height=new int(height);//堆区开辟的对象有程序员开辟也有程序员释放
	}
	
	~person()
	{
		//析构代码:将堆区开辟的数据做释放操作
		if (m_height != NULL)
		{
			delete m_height;
			m_height = NULL;
		}
		cout << "析构函数的调用" << endl;
	}
	int m_age;
	int* m_height;//身高
};

//使用一个已经创建完毕的对象来初始化一个对象
void test01()
{
	person p1(20,163);
	cout << "p1的年龄为:" << p1.m_age<<"p1的身高为:" <<*p1.m_height<< endl;
	person p2(p1);
	cout << "p2的年龄为:" << p2.m_age << "p2的身高为:" << *p2.m_height << endl;
}


int main()
{
	cout << "01" << endl;
	test01();
	system("pause");
	return 0; 
}

 2.浅拷贝问题解决:利用深拷贝解决

  • 自己实现拷贝构造函数,解决浅拷贝带来的问题
  • 深拷贝
  • 重新开辟一个堆区,也就是原先的p1指向的堆区是一个,而现在的p2指向的堆区是另一个
​person(const person &p)//拷贝函数
	{
		cout << "拷贝函数的调用" << endl;
		m_age = p.m_age;
		//m_height = height;//编译器默认的拷贝函数的代码
		//深拷贝操作
		m_height = new int(*p.m_height);
	}

六.初始化列表
  • 作用:用来初始化属性
  • 语法:构造函数():属性1(值1),属性2(值2)....{}
#include
using namespace std;

class person
{
public:
	//传统初始化操作
	
	//初始化列表初始属性
	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(10, 20, 30);
	person p(10,20,30);
	cout << "m_a:" << p.m_a << endl;
	cout << "m_b:" << p.m_b << endl; 
	cout << "m_b:" << p.m_c << endl;
}

int main()
{
	test01();
	system("pause");
	return 0; 
}
七.类对象最为类成员
  • 对象成员:类中的成员是另一个类的对象
  • class A
    {
    
    }
    class B
    {
      A a;//B类中对象A作为成员,A叫做对象成员
    }
  • 当其他类的对象作为本类的成员,先构造其他类,再构造自身;析构的顺序与构造相反 
  • #include
    using namespace std;
    #include
    
    class phone
    {
    public:
    	phone(string pname)
    	{
    		cout << "phone构造函数调用" << endl;
    		p_name = pname;
    	}
    	~phone()
    	{
    		cout << "phone析构函数调用" << endl;
    		
    	}
    	string p_name;
    	
    };
    
    class person
    {
    public:
    	//phone p_name=pname  隐式转换法
    	person(string name, string pname) :m_name(name), m_phone(pname)
    	{
    		cout << "person构造函数调用" << endl;
    	}
    	~person() 
    	{
    		cout << "person析构函数调用" << endl;
    	}
    	string m_name;
    	phone  m_phone;
    };
    
    //当其他类的对象作为本类的成员,先构造其他类,再构造自身。
    //析构的顺序与构造相反
    void test01()
    {
    	person p("张三", "苹果MAX");
    	cout << p.m_name << "拿着:" << p.m_phone.p_name << endl;
    }
    int main()
    {
    	test01();
    	system("pause");
    	return 0; 
    }

九.静态成员

静态成员就是在成员变量或成员函数前加“static” 

1.静态成员变量

  • 所有共享同一份数据
  • 在编译阶段分配
  • 类内申明,类外初始化

2.静态成员函数

  • 所有对象共享一个函数
  • 静态成员函数只能访问静态成员变量

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/312239.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号