0815,析构函数,拷贝构造函数,赋值运算符函数

ops/2024/9/25 10:24:35/


来自同济医院的问候

目录

01:对象创建

001.cc

003size.cc 

02:对象销毁

004pointer.cc

005destroytime.cc

03:本类型对象的复制

3.1 拷贝构造函数

006cp.cc

007cptime.cc

008recursion.cc

009rightleft.cc

3.2 赋值运算符函数

010thispointer.cc

 011operator.cc

3.3 三合成原则

作业喵:

01,关于对象概念的描述中,( )是错误的。   A

02,有关析构函数的说法不正确的是( )  C

03,对类的构造函数和析构函数描述正确的是( )。  A

04,有关类的说法不正确的是____。    D

05,一个空类对象占据的空间有多大?会自动创建哪些函数呢?

06,什么情况下,会调用拷贝构造函数?

07,什么是拷贝构造函数,其形态是什么,参数可以修改吗?

08,什么是赋值运算符函数,其形态是什么?什么情况下需要手动提供赋值运算符函数呢?

09,写出下面程序的运行结果()

10,设已经有A,B,C,D 4个类的定义,程序中A,B,C,D析构函数调用顺序为? ABDC(坏)

11,定义一个学生类,其中有3个数据成员:学号、姓名、年龄,以及若干成员函数。同时编写main函数,使用这个类,实现对学生数据的复制、赋值与输出。

01:对象创建

001.cc

#include <iostream>
using std::cout;
using std::endl;class Point{
public:Point():_ix(0),_iy(0){cout<<"Point()"<<endl;}Point(int x,int y=1):_ix(x),_iy(y){cout<<"Point(int ,int)"<<endl;}//不是严格意义的初始化,本质是赋值/* Point(int x,int y){ *//*     _ix=x; *//*     _iy=y; *//*     cout<<"Point(int ,int )"<<endl;} */void print(){ cout<<_ix<<"\t\t"<<_iy<<endl; }
private:int _ix;int _iy;
};
void test(){Point pt1;Point pt2(5);Point pt(1,2);pt1.print();pt2.print();pt.print();
}int main(void)
{test();return 0;
}

003size.cc 

#include <iostream>
using std::cout;
using std::endl;#pragma pack(4)class A{int _num;double _price;
};
class B{int _num;int _price;
};
class C{int _num;int _num1;double _price;
};
class D{int _num;double _price;int _num1;
};
class E{double _e;char _eArr[20];double _e1;int _e2;
};
class F{char _fArr[20];
};
class G{int num;
};
class H{char _gArr[20];int _g1;int _g2;
};
class I {};
void test(){cout<<sizeof(A)<<endl;cout<<sizeof(B)<<endl;//16 8cout<<sizeof(C)<<endl;cout<<sizeof(D)<<endl;//16 24cout<<sizeof(E)<<endl;cout<<sizeof(F)<<endl;//48 24cout<<sizeof(G)<<endl;cout<<sizeof(H)<<endl;cout<<endl;I i1,i2;cout<<&i1<<" "<<&i2<<endl;cout<<sizeof(I)<<endl;
}int main(void)
{test();return 0;
}

02:对象销毁

004pointer.cc

#include <iostream>
#include <string.h>
using std::cout;
using std::endl;class Computer{
public:Computer(const char* brand,double price): _brand(new char[strlen(brand)+1]()), _price(price){strcpy(_brand,brand);// 否则没有赋值喵,不输出cout<<"Computer"<<endl;}~Computer(){if(_brand){delete []  _brand;  //coution_brand=nullptr;   //加上,信任行为喵}cout<<"~Computer"<<endl;}void printBrandPrice(){cout<<"brand:"<<_brand<<"\t\t";cout<<"price:"<<_price<<endl;}
private:/* char _brand[20]; */char* _brand;double _price;
};void test(){Computer pc("dell",20000);pc.printBrandPrice();//对象销毁时一定会调用析构函数,析构函数执行完,对对象没有被销毁//defecate indiscriminately pc.~Computer();/* pc.printBrandPrice();  //locked */cout<<"over "<<endl;
}
void test01(){const char *p="i love xixi";int * pp=nullptr;cout<<p<<endl;cout<<pp<<endl; //0p=nullptr;//C++会自动访问char*类型指针,此处访问了空指针/* cout<<p<<endl; */cout<<"OK OK OK"<<endl;
}
int main(void)
{test();test01();return 0;
}

005destroytime.cc

#include <iostream>
#include <string.h>
using std::cout;
using std::endl;class Computer{
public:Computer(const char* brand,double price): _brand(new char[strlen(brand)+1]()), _price(price){strcpy(_brand,brand);// 否则没有赋值喵,不输出cout<<_brand<<"\t\t"<<"Computer"<<endl;}~Computer(){cout<<_brand<<"\t\t";if(_brand){delete []  _brand;  //coution_brand=nullptr;   //加上,信任行为喵}cout<<"~Computer"<<endl;}void printBrandPrice(){cout<<_brand<<"\t";cout<<_price<<endl;}
private:/* char _brand[20]; */char* _brand;double _price;
};Computer pc_static("huipu__1",40000);
void test(){Computer pc("dell__2",20000);pc.printBrandPrice();Computer pc_kaixin("honor__3",0);pc_kaixin.printBrandPrice();static Computer pc_jiajia("vsus__4",10000);pc.printBrandPrice();pc_jiajia.printBrandPrice();pc_static.printBrandPrice();Computer* p_new=new Computer("lengion__5",8000);p_new->Computer::printBrandPrice();delete p_new;p_new=nullptr;//坏  后创建的先销毁
}
void test01(){
}
int main(void)
{test();test01();return 0;
}

03:本类型对象的复制

3.1 拷贝构造函数

006cp.cc

#include <iostream>
#include <string.h>
using std::cout;
using std::endl;class Computer{
public:Computer(const char* brand,double price): _brand(new char[strlen(brand)+1]()), _price(price){strcpy(_brand,brand);// 否则没有赋值喵,不输出cout<<_brand<<"\t\t"<<"Computer"<<endl;}Computer(const Computer & pc): _brand(new char[strlen(pc._brand)+1]()), _price(pc._price){strcpy(_brand,pc._brand);// 否则没有赋值喵,不输出cout<<_brand<<"\t\t"<<"Copy  Computer"<<endl;}~Computer(){cout<<_brand<<"\t\t";if(_brand){delete []  _brand;  //coution_brand=nullptr;   //加上,信任行为喵}}void printBrandPrice(){cout<<_brand<<"\t";cout<<_price<<endl;}
private:/* char _brand[20]; */char* _brand;double _price;
};void test(){int x=10;int y=x;cout<<x<<endl;cout<<y<<endl;Computer pc("dell",20000);pc.printBrandPrice();/* Computer pp=pc; */Computer pp(pc);pp.printBrandPrice();//坏,double free//original cpy浅拷贝喵}int main(void)
{test();return 0;
}

007cptime.cc

#include <iostream>
using std::cout;
using std::endl;class Point{
public:Point():_ix(0),_iy(0){cout<<"Point()"<<endl;}Point(int x,int y=1):_ix(x),_iy(y){cout<<"Point(int ,int)"<<endl;}Point(const Point & p):_ix(p._ix),_iy(p._iy){cout<<"Point(Point &)"<<endl;}void print(){ cout<<_ix<<"\t\t"<<_iy<<endl; }
private:int _ix;int _iy;
};//Point p=pt3
void func(Point p){p.print();
}
//第二种调用时机 实参和形参都是对象(用实参初始化形参的过程也会调用拷贝构造)
//避免多余复制,写成引用形式
void func01(Point &  p){p.print();
}
Point pp(258,258);
Point func02(){ return pp; }
//函数的返回值时对象时,执行return语句会调用拷贝构造
Point & func03(){ return pp; }
//避免这次复制可以将返回值写为引用
//caution live_timevoid test(){Point pt1;Point pt2(5);Point pt(1,2);Point pt3(pt1);//第一种调用时机 初始化cout<<endl;func(pt3);func01(pt3);//第2种调用时机 cout<<endl;func03().print();func02().print();//第3种调用时机 /* pt1.print(); *//* pt2.print(); *//* pt.print(); *//* pt3.print(); */
}int main(void)
{test();return 0;
}

008recursion.cc

#include <iostream>
using std::cout;
using std::endl;class Point{
public:Point():_ix(0),_iy(0){cout<<"Point()"<<endl;}Point(int x,int y=1):_ix(x),_iy(y){cout<<"Point(int ,int)"<<endl;}/* Point(const Point & p) *//*     :_ix(p._ix),_iy(p._iy) *//*     {cout<<"Point(Point &)"<<endl;} *//* Point( Point & p) *//*     :_ix(p._ix),_iy(p._iy) *//*     {cout<<"Point(Point &)"<<endl;} *///保证右操作数不被修改,为了能够复制临时对象的Point(const Point  p):_ix(p._ix),_iy(p._iy){cout<<"Point(Point &)"<<endl;}//const Point p=pt1,触发拷贝构造函数,陷入递归拷贝喵void print(){ cout<<_ix<<"\t\t"<<_iy<<endl; }
private:int _ix;int _iy;
};void test(){Point pt1(30,50);Point pt3(pt1);pt1.print();/* pt3.print(); *///error /* Point pt4=Point(20,20); *//* pt4.print(); *///坏,我的好想能跑
}int main(void)
{test();return 0;
}

009rightleft.cc

#include <iostream>
using std::cout;
using std::endl;class Point{
public:Point():_ix(0),_iy(0){cout<<"Point()"<<endl;}Point(int x,int y=1):_ix(x),_iy(y){cout<<"Point(int ,int)"<<endl;}Point(const Point & p):_ix(p._ix),_iy(p._iy){cout<<"Point(Point &)"<<endl;}void print(){ cout<<_ix<<"\t\t"<<_iy<<endl; }
private:int _ix;int _iy;
};void test(){int a=10;int b=20;cout<<&a<<endl;cout<<&(++a)<<endl;//左值  能取地址/* cout<<&(a++)<<endl; *//* cout<<&(a+b)<<endl; *///右值 不能 (临时变量/匿名对象,临时对象,字面值//&1  存在与指令系统,不存在内存中Point pt(1,1);cout<<&pt<<endl;cout<<endl;int & ref=a;const int & ref1=b;/* int & ref2=a+b; *///no const=left//const = left or rightconst int & ref4=a+b;/* printf("%p\n",ref); *//* printf("%p\n",ref1); *//* printf("%p\n",ref4); */
}int main(void)
{test();return 0;
}

3.2 赋值运算符函数

010thispointer.cc

#include <iostream>
using std::cout;
using std::endl;class Point{
public:Point():_ix(0),_iy(0){cout<<"Point()"<<endl;}Point(int x,int y=1):_ix(x),_iy(y){cout<<"Point(int ,int)"<<endl;}Point(const Point & p):_ix(p._ix),_iy(p._iy){cout<<"Point(Point &)"<<endl;}//Point * const this//不能修改指向,”本对象“的地址//隐藏成员函数参数Point & operator=(const Point & p){cout<<"operator="<<endl;/* this->_ix=p._ix; *//* this->_iy=p._iy; */_ix=p._ix;_iy=p._iy;return *this;}void print(){ cout<<_ix<<"\t\t"<<_iy<<endl; }
private:int _ix;int _iy;
};void test(){Point p(10,30);Point p1;p1.print();p1=p;/* pt.operator=(pt2);//本质形式 */p1.print();cout<<endl;int x=10,y=100;cout<<&(x=y)<<endl;cout<<&x<<endl;
}int main(void)
{test();return 0;
}

 011operator.cc

#include <iostream>
#include <string.h>
using std::cout;
using std::endl;class Computer{
public:Computer(const char* brand,double price): _brand(new char[strlen(brand)+1]()), _price(price){strcpy(_brand,brand);// 否则没有赋值喵,不输出}Computer(const Computer & pc): _brand(new char[strlen(pc._brand)+1]()), _price(pc._price){strcpy(_brand,pc._brand);// 否则没有赋值喵,不输出}Computer & operator=(const Computer & c){cout<<"operator ="<<endl;if(this!=&c){//1 考虑自赋值的情况delete [] _brand;//2  回收原本管理的堆空间_brand=new char[strlen(c._brand)+1]();strcpy(_brand,c._brand);//3  深拷贝_price=c._price;}return *this;//4  返回本对象}~Computer(){if(_brand){delete []  _brand;  //coution_brand=nullptr;   //加上,信任行为喵}}void printBrandPrice(){cout<<_brand<<"\t";cout<<_price<<endl;}
private:/* char _brand[20]; */char* _brand;double _price;
};void test(){Computer pc("dell",20000);Computer pc1("cici",20000);pc.printBrandPrice();/* Computer pp=ps; */Computer pp(pc);pp.printBrandPrice();//坏,double free//original cpy浅拷贝喵pc=pc;pc.printBrandPrice();pc=pc1;pc.printBrandPrice();}int main(void)
{test();return 0;
}

3.3 三合成原则

作业喵:

01,关于对象概念的描述中,( )是错误的。   A

  • A对象就是C语言中的结构体

  • B对象是状态和操作的封装体

  • C对象之间的信息传递是通过消息进行的

  • D对象是某个类的一个实例

02,有关析构函数的说法不正确的是( )  C

  • A析构函数有且只有一个

  • B析构函数无任何函数类型

  • C析构函数和构造函数一样可以有形参

  • D析构函数的作用是在对象被撤销时收回先前分配的内存空间

03,对类的构造函数和析构函数描述正确的是( )。  A

  • A构造函数可以重载,析构函数不能重载

  • B构造函数不能重载,析构函数可以重载

  • C构造函数可以重载,析构函数也可以重载

  • D构造函数不能重载,析构函数也不能重载

04,有关类的说法不正确的是____。    D

  • A类是一种用户自定义的数据类型

  • B只有类中的成员函数才能存取类中的私有数据

  • C在类中,如果不作特别说明,所有的数据均为私有类型

  • D在类中,如果不作特别说明,所有的成员函数均为公有类型

05,一个空类对象占据的空间有多大?会自动创建哪些函数呢?

空类:1个字节,仅仅是编译器的一种占位机制

自动创建的函数:默认无参构造,默认析构,默认拷贝构造(浅拷贝),赋值运算符函数(浅拷贝的那种喵)

06,什么情况下,会调用拷贝构造函数?

1,用已经存在的对象给新建的对象初始化

(以下为不看代码十分抽象内容)

2,函数参数(实参和形参的类型都是对象),形参与实参结合时(实参初始化形参)
避免不必要的拷贝,可以使用引用作为参数

3,函数的返回值是对象(return 会 copy)
避免多余拷贝,用引用作为返回值,确保返回值的生命周期大于函数的生命周期

07,什么是拷贝构造函数,其形态是什么,参数可以修改吗?

1,用一个已经存在的同类型的对象来初始化新对象的 构造函数

2,类名  (const 类名 & )

3,不可以
3.1  不可以去掉引用符号(遇到第二种调用时机“形参实参都是对象,用实参初始化形参”的时候,会再一次调用拷贝构造,导致递归调用
3.2  不可以去掉const   (1,确保右操作数的数据成员不会被改变,2,为了能够赋值临时对象的内容,非const引用不能绑定临时变量)

08,什么是赋值运算符函数,其形态是什么?什么情况下需要手动提供赋值运算符函数呢?

1,用已经创建的对象给另一个对象赋值的时候,会调用赋值运算函数(没有自定义时,系统会提供一个默认版本(浅拷贝版本))

2,类名 & operator =   (const 类名 &)

3,当拷贝构造,析构函数,赋值运算符手动定义了其中任何一个,其他两个也都需要手动定义

09,写出下面程序的运行结果()

class Sample 
{int i;
public:Sample();Sample(int val);void Display();~Sample();
};Sample::Sample() 
{cout << "Constructor1" << endl;i=0;
}Sample::Sample(int val) 
{cout << "Constructor2" << endl;i=val;
}void Sample::Display() 
{cout << "i=" << i << endl;
}Sample::~Sample() 
{cout << "Destructor" << endl;
}int main() 
{Sample a, b(10);a.Display();b.Display();return 0;
}

Constructor1
Constructor2
i=0
i=10
Destructor
Destructor 

10,设已经有A,B,C,D 4个类的定义,程序中A,B,C,D析构函数调用顺序为? ABDC(坏)

C c;
int main()
{A *pa=new A();B b;static D d;delete pa;return 0;
}

A  B  D  C  (坏,后创建的先销毁

1,堆对象,delete删除时

2,全局对象,整个程序结束时

3,静态对象,整个程序结束时

4,局部对象,程序离开局部对象的作用域时

11,定义一个学生类,其中有3个数据成员:学号、姓名、年龄,以及若干成员函数。同时编写main函数,使用这个类,实现对学生数据的复制、赋值与输出。

#include <iostream>
#include <string.h>
using std::cout;
using std::endl;class Student{
public:Student(int id,int age,const char* name):_id(id),_age(age),_name(new char[strlen(name)+1]()){strcpy(_name,name);}Student(const Student & s):_id(s._id),_age(s._age),_name(new char[strlen(s._name)+1]()){strcpy(_name,s._name);}Student & operator=(const Student & s){if(this!=&s){_id=s._id;_age=s._age;delete [] _name;_name=new char[strlen(s._name)]();strcpy(_name,s._name);}return *this;}~Student(){cout<<_name<<" ";if(_name){delete [] _name;_name=nullptr;cout<<"love xixi"<<endl;}}void printStudent(){cout<<_id<<"\t"<<_age<<"\t"<<_name<<endl;}
private:int _id;int _age;char* _name;
};
void test(){Student jia(1,21,"jiajia");jia.printStudent();Student kai(1,21,"kaixin");jia.printStudent();Student hui(kai);hui.printStudent();hui=jia;hui.printStudent();
}int main(void)
{test();return 0;
}

1    21    jiajia
1    21    jiajia
1    21    kaixin
1    21    jiajia
jiajia love xixi
kaixin love xixi
jiajia love xixi     //只调用了三次析构函数喵    是我  en~~~?


http://www.ppmy.cn/ops/95005.html

相关文章

jar包在linux无法直接获取resources文件夹下的文件

windows下&#xff0c;通过hutool的FileUtil.file()就可以获取到文件&#xff0c;通过MailUtil.send()将邮件带附件的方式成功&#xff0c;携带附件发邮件。 linux下部署&#xff0c;截图中的FileUtil.file()是拿不到文件的&#xff0c;报IOException while sending message&a…

[论文笔记]ZeRO: Memory Optimizations Toward Training Trillion Parameter Models

引言 今天带来ZeRO: Memory Optimizations Toward Training Trillion Parameter Models的论文笔记。 大型深度模型提供了显著的准确性提升&#xff0c;但训练数十亿到数万亿个参数是具有挑战性的。现有的解决方案&#xff0c;如数据并行和模型并行&#xff0c;存在基本的局限…

drools规则引擎 规则配置文件drl语法使用案例

前提&#xff1a;环境搭建&#xff0c;参考博文springboot整合drools规则引擎 示例入门-CSDN博客案例1&#xff0c;商城系统消费赠送积分 100元以下, 不加分 100元-500元 加100分 500元-1000元 加500分 1000元 以上 加1000分订单pojo编写 package cn.beijing.model;import lom…

【Py/Java/C++三种语言详解】LeetCode743、网络延迟时间【单源最短路问题Djikstra算法】

可上 欧弟OJ系统 练习华子OD、大厂真题 绿色聊天软件戳 od1441了解算法冲刺训练&#xff08;备注【CSDN】否则不通过&#xff09; 文章目录 相关推荐阅读一、题目描述二、题目解析三、参考代码PythonJavaC 时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 相关推荐阅读 …

Oracle-OraclePartition

提示&#xff1a;OraclePartition 是 Debezium 中用于跟踪和处理 Oracle 数据库分区变更的核心组件之一。 文章目录 前言一、核心功能二、代码分析总结 前言 提示&#xff1a;OraclePartition 类用于标识和管理 Oracle 数据库中的逻辑分区&#xff0c;支持数据同步任务中的分区…

Flutter-->使用dart编写蒲公英上传脚本

之前写过使用gradle groovy语言写过一次: AS–›Gradle上传文件至蒲公英-CSDN博客 这次使用dart语言与时俱进. 蒲公英上传文档请查看 Pgyer - FAQ - API 2.0 脚本特性: 支持当前最新的蒲公英接口2.0支持apk和ipa文件后缀支持飞书Webhook通知 脚本配置 脚本自动读取项目根…

Android笔试面试题AI答之Kotlin(14)

文章目录 64. Kotlin中定义函数还是属性场景?使用属性的场景使用函数的场景示例 65. 阐述Kotlin中变量初始化有几种?其中lateinit、by lazy、delegates.notNull有什么区别 &#xff1f;Kotlin中变量初始化的几种方式lateinit、by lazy、Delegates.notNull的区别 66. Kotlin中…

Vision Transformer学习笔记

论文链接&#xff1a;https://arxiv.org/abs/2010.11929 项目链接&#xff1a;https://github.com/google-research/vision_transformer 本文代码链接&#xff1a;https://gitcode.com/gh_mirrors/de/deep-learning-for-image-processing/tree/master/pytorch_classification/v…