1、对象的初始化和相互赋值问题
#include <iostream>
using namespace std;
class MyClass
{
public:
int a;
int b;
char c;
};
void test1()
{
//类实例化的对象可以像结构体变量一样进行初始化,不建议使用
//由于一般成员变量都是私有的,所以无法使用这种方式,也很少使用
MyClass m1 = {100, 200, 'w'};
cout << m1.a << " " << m1.b << " " << m1.c << endl;
//类的对象之间也可以直接赋值
MyClass m2 = m1;
cout << m2.a << " " << m2.b << " " << m2.c << endl;
//注意:
// 在实例化对象时将一个对象赋值给实例化的对象
// 与已经定义好的对象赋值时完全不同的
// 实例化时通过对象赋值调用的是拷贝构造函数
// 已经定义好的对象赋值时运算符重载
MyClass m3;
m3 = m1;
cout << m3.a << " " << m3.b << " " << m3.c << endl;
}
int main(int argc, char *argv[])
{
test1();
return 0;
}
2、浅拷贝和深拷贝
!如果不涉及指针变量赋值,不会出现浅拷贝和深拷贝
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
class Person
{
public:
void setID(int id)
{
p_ID = id;
}
void setName(char *name)
{
p_Name = new char[strlen(name) + 1];
strcpy(p_Name, name);
}
void getMsg()
{
cout << p_ID << " " << p_Name << endl;
printf("p_Name = %p\n", p_Name);
}
void FreeMemory()
{
delete []p_Name;
}
int getID()
{
return p_ID;
}
char *getName()
{
return p_Name;
}
private:
int p_ID;
char *p_Name;
};
//浅拷贝:本质就是值传递
//如果涉及到指针变量,有可能只会开辟一块空间
//此时如果要释放空间,就会对同一块空间释放两次,就会出现错误,内存溢出,程序异常退出
void test1()
{
Person p1;
p1.setID(1001);
p1.setName("zhangsan");
p1.getMsg();
Person p2 = p1; //p_ID2 = p_ID1 p_Name2 = p_Name1
p2.getMsg();
p1.FreeMemory();
p2.FreeMemory();
}
//深拷贝:当类中的成员变量涉及指针变量时,分别开辟空间,释放时不会有影响
void test2()
{
Person p1;
p1.setID(1001);
p1.setName("zhangsan");
p1.getMsg();
Person p2;
p2.setID(p1.getID());
p2.setName(p1.getName());
p1.getMsg();
p1.FreeMemory();
p2.FreeMemory();
}
//浅拷贝
void test3()
{
char *p = new char[32];
strcpy(p, "hello world");
char *q = p;
cout << "p = " << p << endl;
cout << "q = " << q << endl;
delete []p;
delete []q;
}
//深拷贝
void test4()
{
char *p = new char[32];
strcpy(p, "hello world");
char *q = new char[strlen(p) + 1];
strcpy(q, p);
cout << "p = " << p << endl;
cout << "q = " << q << endl;
delete []p;
delete []q;
}
int main(int argc, char *argv[])
{
test4();
return 0;
}
3、构造函数
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
//定义构造函数
//构造函数与当前类的名字必须一样,并且没有返回值,连void也不能写
//构造函数可以后参数也可以没有,并且构造函数可以函数重载,也可以使用缺省参数
//系统默认就会创建构造函数,但是如果自定义了,系统默认的构造函数将不会调用
Person()
{
cout << "无参构造函数" << endl;
}
Person(int id, string name, int age, string eid)
{
cout << "有参构造函数" << endl;
p_ID = id;
p_Name = name;
p_Age = age;
p_Eid = eid;
}
void getMsg()
{
cout << p_ID << " " << p_Name << " " << p_Age << " " << p_Eid << endl;
}
private:
int p_ID;
string p_Name;
int p_Age;
string p_Eid;
};
void test1()
{
Person p1;
Person p2(1001, "zhangsan", 20, "20000-09-11");
p2.getMsg();
}
int main(int argc, char *argv[])
{
test1();
return 0;
}
4、析构函数
析构函数是对成员变量进行释放空间操作,跟类实例化的对象的释放空间没有任何关系
析构函数主要用于成员变量是一个指针变量并且赋值时在堆区开辟空间,使用完毕后会调用析构函数进行释放空间,如果成员变量不涉及指针变量和堆区空间,析构函数就没有用
析构函数主要用于对成员变量进行释放空间,但是析构函数调用时机是有对象决定的
当对象释放空间时,才会调用析构函数
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person()
{
cout << "无参构造函数" << endl;
}
Person(int id, string name, int age, string eid)
{
cout << "有参构造函数" << endl;
p_ID = id;
p_Name = name;
p_Age = age;
p_Eid = eid;
}
//析构函数
//析构函数的函数名与类名一致,没有返回值,连void也不能有,也没有参数,在函数名前需要加~
~Person()
{
//cout << p_ID << endl;
cout << "析构函数" << endl;
}
void getMsg()
{
cout << p_ID << " " << p_Name << " " << p_Age << " " << p_Eid << endl;
}
private:
int p_ID;
string p_Name;
int p_Age;
string p_Eid;
};//s1; //类实例化的全局对象,在main函数执行前调用构造函数,在main执行结束后调用析构函数
//析构函数主要用于对成员变量进行释放空间,如果成员变量没有指针,则析构函数也没有必要去写
//析构函数的调用时机依据对象的释放空间的实际,对象释放空间就会立即调用析构函数
void test1()
{
//栈区开辟的空间会随着当前代码段的结束而释放空间,所以函数结束,对象释放空间,析构函数就会调用
Person p1;
Person p2(1001, "zhangsan", 20, "1999-01-01");
cout << "----------------" << endl;
}
void test2()
{
//堆区开辟空间,手动申请手动释放,所以当执行delete时,对象释放空间,就会立即执行析构函数
Person *p1 = new Person();
cout << "----------------" << endl;
delete p1;
cout << "^^^^^^^^^^^^^^^^^" << endl;
}
int main(int argc, char *argv[])
{
test2();
cout << "***************" << endl;
return 0;
}
5、拷贝构造函数
拷贝构造函数主要用于当实例化对象时另一个对象对其进行赋值时会使用拷贝构造函数
拷贝构造函数如果要自定义,一般也是涉及到成员变量是指针的时候
如果成员变量没有指针,则系统默认的拷贝构造函数就够了,本质就是值传递
如果自己定义了拷贝构造函数,系统默认的拷贝构造函数就不会再调用
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person()
{
cout << "无参构造函数" << endl;
}
Person(int id, string name, int age, string eid)
{
cout << "有参构造函数" << endl;
p_ID = id;
p_Name = name;
p_Age = age;
p_Eid = eid;
}
~Person()
{
cout << "析构函数" << endl;
}
//拷贝构造函数
Person(const Person &obj)
{
cout << "拷贝构造函数" << endl;
p_ID = obj.p_ID;
p_Name = obj.p_Name;
p_Age = obj.p_Age;
p_Eid = obj.p_Eid;
}
void getMsg()
{
cout << p_ID << " " << p_Name << " " << p_Age << " " << p_Eid << endl;
}
private:
int p_ID;
string p_Name;
int p_Age;
string p_Eid;
};
void test1()
{
Person p1 = Person(1001, "zhangsan", 20, "1999-09-09");
p1.getMsg();
//当实例化对象时,使用另一个对象对当前对象进行赋值时才会调用拷贝构造函数
Person p2 = p1;
p2.getMsg();
cout << "*********************" << endl;
Person p3;
//注意:此时一定不会调用拷贝构造函数,使用的是运算符重载
p3 = p1;
p3.getMsg();
}
int main(int argc, char *argv[])
{
test1();
return 0;
}