c++的一些小语法
内存对齐规则
1.第一个成员函数在与结构体偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
3.对齐数一般为编译器默认的一个对齐数与该成员大小的比较小的值
4.结构体的大小为:最大对齐数(所有变量最大者与默认对齐数参数取最小)的整数倍
5.如果嵌套了结构体,算两步,嵌套的结构体对齐到自己的最大对齐整数倍中,结构体的整体大小就是所有最大对齐数的整数倍。
6.如果结构体中未声明变量,那么对象的大小为1字节,是为了占位标识对象的存在。
this指针
对象中为了区分不同的对象调用相同的类成员函数,在编译器编译后,类的成员函数默认都会在形参的第一个位置,参加一个当前类的指针,叫做this指针。
class Date{
public:
void Print(int ,year,int month,int day){
//void Print(Date* const this,int year,int month,int day);
this->_year=year;
_month=month;
.....;
}
//这里其实是隐藏了this指针,在c++中规定
//,this指针不能再形参和实参的位置出现,但是可以在函数体中出现。
private:
int _year;
int _month;
int _day;//只是声明没有开空间
}
构造函数
构造函数是特殊的成员函数,是对象实例化是初始化对象。构造函数的本质是代替了Init()功能,构造函数自动调用。
特点:
1.函数名与类名相同
2.无返回值(不用写void)
3.对象实例化时系统会自动调用对应的构造函数
4.构造函数可以重载
5.如果没有写,编译器会自动生成,一个无参构造,对内置成员不做处理,自定义类型成员会调用它的构造函数
6.无参构造函数,全缺省函数构造都叫默认函数构造,不传实参就可以调用的函数,叫默认构造
#include <iostream>
using namespace std;
class MyClass {
public:
//1.无参构造
MyClass() {
cout << "无参构造函数调用" << endl;
}
//2.有参构造
MyClass(int a) {
cout << "有参构造函数调用,参数值为:" << a << endl;
}
//3.全缺省构造
MyClass(int a = 0) {
_a = a;
cout << "全缺省构造函数调用,参数值为:" << a << endl;
}
private:
int _a;
};
int main() {
//调用无参构造
MyClass obj1;
//调用有参构造
MyClass obj2(10);
//这里如果不注释掉会报错,原因是调用有参构造和全缺省构造时会产生二义性
return 0;
}
初始化列表
无论是否显示写初始化列表,每个构造函数都有初始化列表
且初始化是按照声明顺序来给值。
隐式转换
在构造前加explicit就不再支持隐式类型转换
#include <iostream>
using namespace std;
class A {
public:
A(int data = 0)
:_data(data)//初始化列表
, _ref(_data)
{
};
A(int data, int data1)
:_data(data), _data1(data1)//初始化列表
, _ref(_data)
{
};
void PrintData()const {
cout << _data << _data1 << endl;
}
private:
int _data;
int _data1;
int& _ref;//引用成员必须初始化
const int _a = 0; //const成员必须初始化
};
int main() {
A a = 2;
//阴式类型转换,2先构造一个A的临时对象,然后用这个临时对象拷贝构造a
//编译器遇到连续的构造+拷贝构造——》优化为直接构造
//explict关键字可以阻止隐式类型转换
a.PrintData();
const A& b = 3;
//b.PrintData();//eroor
const A& c = { 4,5 };//,const 引用可以绑定到临时对象(延长其生命周期)。
c.PrintData();
// const 修饰的对象(或通过 const 引用访问的对象),只能调用 const 成员函数。
// 这是因为非 const 成员函数可能会修改对象的成员变量,而 const 对象的状态不允许被修改。
return 0;
}
static成员
用static修饰的成员变量,一定要在类外进行初始化,静态成员为所有类对象所共享,不属于某个具体的对象,不存在对象之中,放在静态区。
静态成员没有this指针
静态成员可以访问其他静态成员,但不能访问非静态的,非静态可以任意访问。
静态成员不能再声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表
#include <iostream>
using namespace std;
class A {
public:
static int _a;//静态成员变量声明
void PrintA() {
cout << _a << endl;
}
};
int A::_a = 10; //静态成员变量定义和初始化
int main() {
A a1;
A a2;
a1.PrintA();
a2.PrintA();
A::_a = 20; //通过类名修改静态成员变量
a1.PrintA();
a2.PrintA();
return 0;
}
析构函数
c++规定对象在销毁是会自动调用析构函数,完成对象中资源的清理释放。
特点:
1.函数名前加~
2.无参数返回值
3.一个类只能有一个析构函数,若未定义,系统会自动默认生成析构函数
4.对象生命周期结束时系统会自动调用析构函数
5.跟构造函数一样,我们不写,编译器会自动生成析构函数对内置成员不做处理,自定义类型成员会调用它的析构函数。
6.自定义类的成员无论什么情况都会调用析构函数。
//析构函数
~MyClass() {
cout << "析构函数调用" << endl;
}//自己调用自己
程序结束,自己调用
拷贝构造
拷贝构造是一个特殊的构造函数
特点:
- 拷贝构造就是构造函数的一个重载
- 第一个参数必须是类型对象的引用,使用传值方式编译直接回报错,传值会产生一个临时对象,对象再去调用对象的拷贝构造,就会无限递归。且后面的参数必须有缺省值
- 未定义时,编译器自动生成,自动生成的拷贝构造,对内置类型会完成值拷贝(浅拷贝),对自定义类型对调用它的拷贝构造函数。
- 深拷贝需要自己去定义
MyClass(const MyClass& obj) {
_a = obj._a;
cout << "拷贝构造函数调用,参数值为:" << _a << endl;
}
运算符重载
运算符重载是具有特殊名字的函数,它的名字是由operator和后面要定义的运算符共同构成。和其它函数一样,它也具有其返回类型以及参数列表以及函数体。
class Date
{
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month);
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);
// 拷贝构造函数
// d2(d1)
Date(const Date& d);
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& operator=(const Date& d);
// 析构函数
~Date();
// 日期+=天数
Date& operator+=(int day);
// 日期+天数
Date operator+(int day);
// 日期-天数
Date operator-(int day);
// 日期-=天数
Date& operator-=(int day);
// 前置++
Date& operator++();
// 后置++
Date operator++(int);
// 后置--
Date operator--(int);
// 前置--
Date& operator--();
// >运算符重载
bool operator>(const Date& d);
// ==运算符重载
bool operator==(const Date& d);
// >=运算符重载
bool operator >= (const Date& d);
// <运算符重载
bool operator < (const Date& d);
// <=运算符重载
bool operator <= (const Date& d);
// !=运算符重载
bool operator != (const Date& d);
// 日期-日期 返回天数
int operator-(const Date& d);
private:
int _year;
int _month;
int _day;
};
// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
// 拷贝构造函数
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// 赋值运算符重载
Date& Date::operator=(const Date& d)
{
if (this != &d) // 防止自赋值
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{
static int days[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
// 闰年2月29天
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
days[1] = 29;
}
return days[month - 1];
}
// 析构函数
Date::~Date()
{
}
// 日期+=天数
Date& Date::operator+=(int day)
{
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
}
return *this;
}
// 日期+天数
Date Date::operator+(int day)
{
Date temp = *this;
temp += day;
return temp;
}
// 日期-天数
Date Date::operator-(int day)
{
Date temp = *this;
temp -= day;
return temp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
_day -= day;
while (_day <= 0)
{
_month--;
if (_month <= 0)
{
_month = 12;
_year--;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
// 前置++
Date& Date::operator++()
{
*this += 1;
return *this;
}
// 后置++
Date Date::operator++(int)
{
Date temp = *this;
*this += 1;
return temp;
}
// 后置--
Date Date::operator--(int)
{
Date temp = *this;
*this -= 1;
return temp;
}
// 前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
// >运算符重载
bool Date::operator>(const Date& d)
{
if (_year != d._year)
return _year > d._year;
if (_month != d._month)
return _month > d._month;
return _day > d._day;
}
// ==运算符重载
bool Date::operator==(const Date& d)
{
return _year == d._year && _month == d._month && _day == d._day;
}
// >=运算符重载
bool Date::operator>=(const Date& d)
{
return (*this > d) || (*this == d);
}
// <运算符重载
bool Date::operator<(const Date& d)
{
return !(*this >= d);
}
// <=运算符重载
bool Date::operator<=(const Date& d)
{
return !(*this > d);
}
// !=运算符重载
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
Date temp1 = *this;
Date temp2 = d;
int days1 = 0;
int days2 = 0;
// 计算当前日期到1900年1月1日的天数
for (int year = 1900; year < temp1._year; year++)
{
days1 += 365;
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
days1++;
}
for (int month = 1; month < temp1._month; month++)
{
days1 += GetMonthDay(temp1._year, month);
}
days1 += temp1._day;
// 计算另一个日期到1900年1月1日的天数
for (int year = 1900; year < temp2._year; year++)
{
days2 += 365;
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
days2++;
}
for (int month = 1; month < temp2._month; month++)
{
days2 += GetMonthDay(temp2._year, month);
}
days2 += temp2._day;
return days1 - days2;
}
int main() {
Date d1(2024, 3, 14);
Date d2 = d1; // 调用拷贝构造函数
Date d3;
d3 = d1; // 调用赋值运算符重载
Date d4 = d1 + 10; // 日期加天数
Date d5 = d1 - 5; // 日期减天数
d1 += 20; // 日期加天数
d2 -= 15; // 日期减天数
++d1; // 前置++
d2++; // 后置++
--d3; // 前置--
d4--; // 后置--
bool b1 = d1 > d2; // 大于比较
bool b2 = d3 == d4; // 等于比较
int daysDiff = d1 - d2; // 日期差值
return 0;
}
更多推荐



所有评论(0)