来自同济医院的问候
目录
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 8
cout<<sizeof(C)<<endl;
cout<<sizeof(D)<<endl;
//16 24
cout<<sizeof(E)<<endl;
cout<<sizeof(F)<<endl;
//48 24
cout<<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; //0
p=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_time
void 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 right
const 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~~~?