目录
1.空类
2.构造函数
3析构函数
4.拷贝构造
5.赋值构造
6.取地址函数重载
7.初始化列表
8.隐含的this指针
空类是没有任何成员属性的类
空类对象在内存中仍然 占据至少 1 字节空间,以确保不同对象地址不同(否则两个对象地址可能一样,无法区分)。
C++类的计算大小和C语言的结构体是一样的,不需要计算C++类的成员方法。
下面两种叫法是一样的
C++类的变量和函数
C++类的成员属性和成员方法
C++类只需要存储成员属就行了,成员方法都是要一样的,只是处理不同对象的数据而已。
创建一个类就相当于自定义一个数据类型,首先是声明,然后是定义
1.没有自定义构造函数
#include
using namespace std;
class date
{
public:
date(int year = 2000,int month = 4, int day = 10)
:_year(year)
,_month(month)
,_day(day)
// c++初始化列表才是成员属性定义的地方
{
cout<< " date " <<endl;
}
void print()
{
cout<< this->_year << " " << this->_month << " " << this->_day <<endl;
}
private:
int _year;
int _month;
int _day;
};
class Time
{
public:
// 这里有问题还需要研究一下!!!
//Time(int hour = 1, int mintes = 1, int second = 1)
// :_hour(hour)
// ,_mintes(mintes)
// ,_second(second)
Time()
{
cout<< " time " <<endl;
}
private:
int _hour;
int _mintes;
int _second;
};
class date2
{
public:
void print()
{
cout<< this->_year << " " << this->_month << " " << this->_day <<endl;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
int main()
{
// c++会自动调用我们已经写好的构造函数
date d1; // 调用默认的缺省参数
d1.print();
date d2(11,22,33); // 这里面没有进行日期合法的检查!!!! 调用我们传入的参数
d2.print();
// 我们不写构造函数
// 自定义类型编译器会调用它的默认构造函数
date2 d3; // 这里会默认调用自定义类型的构造函数(应该自定义类型默认构造函数)
}
2.自定义构造函数
#include
using namespace std;
class Time {
public:
Time()
{
_hour = 0;
_minute = 0;
_second = 0;
cout << "Time constructor" << endl;
}
void print() const {
cout << _hour << ":" << _minute << ":" << _second;
}
private:
int _hour;
int _minute;
int _second;
};
class Date {
public:
Date(int year = 2000, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
, _t()
{
cout << "Date constructor" << endl;
}
void print() const
{
cout << _year << "-" << _month << "-" << _day << " ";
_t.print();
cout << endl;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
int main() {
Date d1; // 调用 Date(),内部调用 Time()
d1.print();
Date d2(2023, 5, 15); // 调用 Date(2023, 5, 15),内部调用 Time()
d2.print();
return 0;
}
C++强调对自定义类型的数据进行初始化和清理工作。
析构函数,在生命周期结束的时候自动调用析构函数,清理类自己开辟的资源。解决了c语言容易忘记的缺点。
1.没有自定义构造函数
#include
using namespace std;
class a
{
public:
a(int x = 1, int y = 1, int z = 1)
:_x(x)
,_y(y)
,_z(z)
{
cout<< " a的构造函数 " <<endl;
}
~a()
{
cout<< " ~a的析构函数 " <<endl;
}
private:
int _x;
int _y;
int _z;
};
class b
{
private:
int _x;
a _a;
};
int main()
{
b _b;
}
2.自定义析构函数
#include
using namespace std;
class a
{
public:
a(int x = 1, int y = 1, int z = 1)
:_x(x)
,_y(y)
,_z(z)
{
cout<< " a的构造函数 " <<endl;
}
~a()
{
cout<< " ~a的析构函数 " <<endl;
}
private:
int _x;
int _y;
int _z;
};
class b
{
public:
b(int x)
:_x(x)
,_a(2,2,2)
{
cout<< " b的构造函数 " <<endl;
}
~b()
{
cout<< " b的析构函数 " <<endl;
}
private:
int _x;
a _a;
};
int main()
{
b _b;
}
拷贝构造:这里就是用已经存在的对象,去构造一个一一模一样的对象出来。这里面存在深浅拷贝的问题,先来了解浅拷贝。
#include
using namespace std;
class a
{
public:
a(int x = 1, int y = 1, int z = 1)
:_x(x)
,_y(y)
,_z(z)
{
cout<< " a的构造函数 " <<endl;
}
// 拷贝构造无返回值
a(const a& that)
{
if(this != &that)
{
this->_x = that._x;
this->_y = that._y;
this->_z = that._z;
}
}
void print()
{
cout<< this->_x <<endl;
cout<< this->_y <<endl;
cout<< this->_z <<endl;
}
~a()
{
cout<< " ~a的析构函数 " <<endl;
}
private:
int _x;
int _y;
int _z;
};
int main()
{
a a1;
a1.print();
a a2(a1);
a2.print();
a a3 = a1; // 注意这也是拷贝构造,实际上a2并不存在的
}
赋值构造:两个对象都是存在的,只不过是想把一个对象的值赋值给另一个对象而已!
#include
using namespace std;
class a
{
public:
a(int x = 1, int y = 1, int z = 1)
:_x(x)
,_y(y)
,_z(z)
{
cout<< " a的构造函数 " <<endl;
}
// 拷贝构造无返回值
a(const a& that)
{
if(this != &that)
{
this->_x = that._x;
this->_y = that._y;
this->_z = that._z;
}
}
a& operator=(const a& that)
{
if(this != &that)
{
this->_x = that._x;
this->_y = that._y;
this->_z = that._z;
}
return *this; // 为了实现连续复制而已
}
void print()
{
cout<< this->_x <<endl;
cout<< this->_y <<endl;
cout<< this->_z <<endl;
}
~a()
{
cout<< " ~a的析构函数 " <<endl;
}
private:
int _x;
int _y;
int _z;
};
int main()
{
a a4(2,3,4);
a a5(0,0,0);
a4.print();
a5.print();
a4 = a5;
a4.print();
a5.print();
}
就是取到一个对象的地址,当然了,你自己实现 不让编译取到你的类的地址也行的!
这里的重载涉及到 const成员函数的
#include
class A
{
public:
A* operator&()
{
cout << "重载了取地址符号" << endl;
return this;
}
const A* operator&() const
{
cout << "重载了取地址符号" << endl;
return this;
}
};
int main()
{
A a1;
const A a2;
A* p1 = &a1; // 调用 A* operator&()
const A* p2 = &a2; // 调用 const A* operator&() const
}
C++里面有三类成员变量,需要在初始化列表进行初始化
引用成员属性,const修饰的成员属性, 没有默认构造函数的自定义对象
初始化列表和定义的顺序最好 一样,否则会初始化不完全的!!!
#include
using namespace std;
class A
{
public:
A(int x, int y, int z)
:_x(x)
,_y(y)
,_z(z)
{
cout<< " A的初始化 " <<endl;
}
private:
int _x;
int _y;
int _z;
};
class B
{
public:
B(int x = 10, int y = 1000)
:_x(x)
,_y(100)
,_A(2,3,4)
,_r(x)
{
cout<< " B的构造函数 " <<endl;
}
private:
int _x;
const int _y;
A _A;
int& _r;
};
int main() {
B b;
return 0;
}
类在访问自己的变量的时候,实际上已经隐士的传递 了this指针,通过this指针访问数据。同样我们的函数,通过this指针,能够让函数知道我们 处理的数据是哪个对象的。
精简版总结:
在 C++ 中,类的成员函数在调用时会隐式传入一个 this 指针,指向调用该函数的对象。
成员函数正是通过这个 this 指针来访问对象的成员变量,确保函数处理的是当前对象的数据。
虽然成员函数本身只在代码段中保存一份,但通过 this,它就能“知道”当前操作的是哪个对象,从而实现对象的行为。
#include
using namespace std;
class A
{
public:
A(int x, int y, int z)
:_x(x)
,_y(y)
,_z(z)
{
cout<< " A的初始化 " <<endl;
}
void print()
{
cout<< this->_x <<endl;
cout<< this->_y <<endl;
cout<< this->_z <<endl;
}
private:
int _x;
int _y;
int _z;
};
int main() {
A a(1,2,3);
a.print(); // a.print(&a),这里已经把的的地址传递了
return 0;
}