类的定义

类定义的格式

class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后⾯分号不能省 略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的⽅法或 者成员函数。

#include<iostream>
using namespace std;

class Stack 
{
 public:
  void Init(int n=4)//初始化函数
   {
     x=(int*)malloc(sizeof(int)*n);
     if(x==nullptr)
       {
          perror("malloc fail!");
          exit(1);
       }
     capacity=n;
     top=0;
   } 

  void push(int m)//插入函数
  {
    x[top++]=m;
  }
 
  void Top()//取栈顶元素
  {
    return x[top-1];
  }
 private:
  int *x=NULL;
  size_t capacity=0;
  size_t top=0;
};


int main()
{
 Stack st1;
 st1.Init();
 st1.push(1);
 st1.push(2);
 st1.push(3);
 st1.push(4);
 
 cout<<st1.Top()<<endl;
 return 0;
}

为了区分成员变量,⼀般习惯上成员变量会加⼀个特殊标识,如成员变量前⾯或者后⾯加_或者m 开头,注意C++中这个并不是强制的,只是⼀些惯例,具体看公司的要求。

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	d1.Init(2025, 6, 5);
	d1.Print();
	return 0;
}

访问限定符

C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限 选择性的将其接⼝提供给外部的⽤⼾使⽤

public修饰的成员在类外可以直接被访问;

protected和private修饰的成员在类外不能直接被访问,protected和private是⼀样的

访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有 访问限定符,作⽤域就到}即类结束。

• class定义成员没有被访问限定符修饰时默认为private,struct默认为public。

• ⼀般成员变量都会被限制为private/protected,需要给别⼈使⽤的成员函数会放为public

类域

类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员时,需要使⽤::作 ⽤域操作符指明成员属于哪个类域。

类域影响的是编译的查找规则,下⾯程序中Init如果不指定类域Stack,那么编译器就把Init当成全 局函数,那么编译时,找不到array等成员的声明/定义在哪⾥,就会报错。指定类域Stack,就是知 道Init是成员函数,当前域找不到的array等成员,就会到类域中去查找

#include<iostream>

using namespace std;

calss Stack
{
  public:
   void Init(int n=4);
  private:
   int *array;
   size_t capacity;
   size_t top;
};

void Stack::Init(int n=4)//声明和定义分离需要指定类域
{
 array=(int*)malloc(sizeof(int)*n);
 if(array==nullptr)
 {
   perror("malloc fail!");
   exit(1);
 }
}

实例化

• ⽤类类型在物理内存中创建对象的过程,称为类实例化出对象。

• 类是对象进⾏⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只 是声明,没有分配空间,⽤类实例化出对象时,才会分配空间。

• ⼀个类可以实例化出多个对象,实例化出的对象占⽤实际的物理空间,存储类成员变量。

#include<iostream>

using namespace std;
 
class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
    //这里只是声明,没有开辟空间
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;//Data类实例化出的对象d1和dd2

	d1.Init(2025, 6, 5);
	d1.Print();

	d2.Init(2025, 4, 11);
	d2.Print();
	return 0;
}

对象大小

实例化对象的大小也符合内存对齐规则

内存对⻬规则

• 第⼀个成员在与结构体偏移量为0的地址处。

• 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。

• 注意:对⻬数=编译器默认的⼀个对⻬数与该成员⼤⼩的较⼩值。

• VS中默认的对⻬数为8 • 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍。

• 如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩ 就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍

#include<iostream>
using namespace std;
class A
{
public:
	void Print()
	{
		cout << _ch << endl;
	}

private:
	char _ch;
	int i;
};

class B
{
public:
	void Print()
	{

	}
};
class C
{ };

int main()
{
	A a;
	B b;
	C c;

	cout << sizeof(a) << " " << endl;//8
	cout << sizeof(b) << " " << endl;//1
	cout << sizeof(c) << " " << endl;//1
	return 0;
}

this指针

• Date类中有Init与Print两个成员函数,函数体中没有关于不同对象的区分,那当d1调⽤Init和 Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这⾥就要看到C++给了 ⼀个隐含的this指针解决这⾥的问题

• 编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this 指针。⽐如Date类的Init的真实原型为, void Init(Date* const this, int year, int month, int day)

• 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, >_year = year; this

• C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显 ⽰使⽤this指针

构造函数

1:构造函数是特殊的成员函数,构造函数的主要任务不是开空间创造对象,而是对象实例化时初始化对象。

2:构造函数的特点

函数名与类名相同

无返回值(返回值什么都不给void)

构造函数可以重载(可以写多个,定义多种初始化方式)

如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦⽤⼾显 式定义编译器将不再⽣成(程序中是否写了这样一个构造函数)

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个,注:无参构造函数,全缺省构造函数,没有写编译器默认生成的构造函数,都可以认为是默认构造函数

默认构造函数作用:C++把类型分为内置类型(int char......)和自定义类型(class struct......)编译器默认生成构造函数,会对自定义类型调用他的默认构造函数而对内置类型不做处理

总结:不传参数就可以调用的函数就是默认构造函数

#include<iostream>

using namespace std;
class Time
{
public:
	Time(int hour=1,int min=1,int second=1)
	{
		cout << "Time()" << endl;
		_hour = hour;
		_min = min;
		_second = second;
	}
private:
	int _hour;
	int _min;
	int _second;
};
class Date
{
public:
    Date()
    {};//默认构造函数构成函数重载,但是构成调用奇异
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	//对内置类型不做处理(可处理,可不处理)
	int _year;
	int _month;
	int _day;
	//对自定义类型调用该成员的默认构造
	Time _t;
};

int main()
{
	//Date d1(2025, 8, 9);//若给确定值直接按照确定值
	//d1.print();

	Date d2;//若不给确定值就给缺省值
	d2.Print();
	return 0;
}

实践总结:

1.一般情况下构造函数要手动实现

2.只有类似MyQueue成员全是自定义类型可以让编译器自动生成

析构函数

析构函数:析构函数不是完成对对象的本身进行销毁,局部对象的销毁工作由编译器完成,而对象的销毁会自动调用析构函数,完成对象中资源的清理

特性:

1:析构函数名在类名前加‘~’符号

2:无参数无返回值

3:一个类只能有一个析构函数,若未显示定义编译器会自动生成默认的析构函数

4:析构函数不能重载

5:对象生命周期结束时,编译器会自动调用析构函数

using namespace std;
typedef int STDataType;
class Stack
{
public:
    Stack(int n = 4)
    {
        cout<<"Stack(int n=4)"<<endl;//调用该构造函数就会打印
        _a = (STDataType*)malloc(sizeof(STDataType) * n);
        if (nullptr == _a)
        {
            perror("malloc申请空间失败");
               
                return;
        }
        _capacity = n;
        _top = 0;
    }
    ~Stack()
    {
        cout << "~Stack()" << endl;//调用析构函数就会打印
        if(_a)
        {
           free(_a);
           _a = nullptr;
           _top = _capacity = 0;
        }
    }
private:
    STDataType* _a;
    size_t _capacity;
    size_t _top;
};


class MyQueue
{
public:
    
private:
    Stack pushst;
    Stack popst;
};
int main()
{
    Stack st;
    MyQueue mq;
    return 0;
}

注意:析构函数和构造函数类似(内置类型不做处理,自定义类型调用他的析构函数)

1:有资源需要显示清理,就需要显示的写析构函数(malloc出的对象)

2:没有资源需要清理 如:Date(日期类)

      内置类型成员没有资源需要清理,剩下的都是自定义类型,而自定义类型又去调用他的析构函数 如:MyQueue

class MyQueue
{
public:
    
private:
    Stack pushst;(内置类型去调用他的析构函数)
    Stack popst;

    int size=0;(自定义类型不处理)
};

拷贝构造

如果⼀个构造函数的第⼀个参数是⾃⾝类类型的引⽤,且任何额外的参数都有默认值,则此构造函数 也叫做拷⻉构造函数,也就是说拷⻉构造是⼀个特殊的构造函数

特性:

1:拷贝构造函数是构造函数的一个重载形式

2:拷贝构造函数的第一个参数必须是类类型对象的引用,如果使用传值的方式编译器会直接报错,因为语法逻辑上会引发无限递归。拷贝构造函数可以有多个参数,但第一个参数必须是类类型对象的引用,其他参数给缺省值

3:若未显示定义,编译器会自动生成默认的拷贝构造。⾃动⽣成的拷⻉构造对内置类型成 员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义类型成员变量会调⽤他的拷⻉构 造。 

4:像Date这样的类成员函数全是内置类型,没有指定资源编译器自动生成的拷贝构造就可以完成拷贝就是(值拷贝或者浅拷贝)但是像Stack这样虽然是内置类型,但有指向资源_a就不能用编译器自动生成的拷贝构造进行拷贝所以需要我们自己实现深拷贝(对指向的资源进行拷贝)

注意:自定义类型传值传参需要调用拷贝构造

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

    Date(Date &d)//把原先的数据给改了
	{
		d._year=_year;
		d._month=_month;
		d._day=_day;
	}
    
      Date(const Date &d)//权限的缩小
	{
      _year =d._year;
      _month =d._month;
      _day = d._day;
	}


	/*Date (Date *d)
	{
		_year = d->_year;
		_month = d->_month;
		_day = d->_day;
	}*/
	void Print()
	{
		cout << _year<<" " << _month<<" " << _day << endl;
	}
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

int main()
{
	Date d(2024, 4, 5);
	
	Date d2(d);//拷贝构造用同类型的初始化

	d.Print();
	d2.Print();

	/*Date d3(&d);
	d3.Print();*/

	return 0;
}
typedef int STDataType;
class Stack
{
public:
    Stack(int n = 4)
    {
        cout << "Stack(int n=4)" << endl;
        _a = (STDataType*)malloc(sizeof(STDataType) * n);
        if (nullptr == _a)
        {
            perror("malloc申请空间失败");

            return;
        }
        _capacity = n;
        _top = 0;
    }
    //Stack s2=s1;
    Stack(const Stack& st)
    {
        _a = (STDataType*)malloc(sizeof(STDataType) * st._capacity);
        if (_a == NULL)
        {
            perror("malloc申请空间失败");
            return;
        }

        memcpy(_a, st._a, sizeof(STDataType) * st._top);

        _top = st._top;
        _capacity = st._capacity;
    }

    void Push(STDataType data)
    {
        _a[_top] = data;
        _top++;
    }

    STDataType Top()
    {
        return _a[_top - 1];
    }

    void Pop()
    {
        --_top;
    }
    bool Empty()
    {
        return _top == 0;
    }
    ~Stack()
    {
        cout << "~Stack()" << endl;
        if (_a)
        {
            free(_a);
            _a = nullptr;
            _top = _capacity = 0;
        }
    }
private:
    STDataType* _a;
    size_t _capacity;
    size_t _top;
};


int main()
{

    Stack st;
    st.Push(1);
    st.Push(1);

    Stack st1 = st;
    st1.Push(3);
    st1.Push(5);
    
    while (!st.Empty())
    {
        cout << st.Top() << " ";
        st.Pop();
    }
    cout << endl;

    while (!st1.Empty())
    {
        cout << st1.Top() << " ";
        st1.Pop();
    }
    cout << endl;

	return 0;
}

赋值运算符重载

1.运算符重载

运算符被用于“类”类型变量时,C++允许对运算符进行重载构成新的定义。

运算符重载是具有特殊函数名,是由operator和后面要定义的运算符(+、-)共同构成。和其他函数一样,拥有返回值和参数列表以及函数体

重载运算符作用的个数应该和参数一样多,一元运算符有一个参数,二元运算符有两个参数,但二元运算符左侧的运算符传给第一个参数,右侧运算符传给第二个参数

如果重载运算符在类中是一个成员函数,那么他的第一个运算符对象应该传给隐试的this指针,因此运算符重载作为类的成员函数只有一个参数

.*、::、sizeof、?:、.  五种运算符不能进行重载

重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。 C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分

//.*运算符的解析
#include<iostream>

using namespace std;

class A
{
public:
	void Func()
	{
		cout << "void Func()" << endl;
	}

};

typedef void(A::* ptrFunc)();//成员函数指针类型

int main()
{
	//成员函数需要加&才能取到函数指针
	ptrFunc fp = &A::Func;//定义成员函数指针fp指向函数Func

	A temp;//创建类实例化对象

	(temp.*fp)();

	return 0;
}

显示调用不能访问内部私有成员

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
//private:
	int _year;
	int _month;
	int _day;
};

bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year 
		&& d1._month == d2._month 
		&& d1._day == d2._day;
}

int main()
{
	Date d3(2025, 9, 8);
	Date d4(2025, 9, 8);

	//显试调用
	operator==(d3, d4);


	return 0;
}

2.赋值运算符重载

赋值运算符重载是⼀个默认成员函数,⽤于完成两个已经存在的对象直接的拷⻉赋值,这⾥要注意跟 拷⻉构造区分,拷⻉构造⽤于⼀个对象拷⻉初始化给另⼀个要创建的对象

1. 赋值运算符重载是⼀个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成 const 当前类类型引⽤,否则会传值传参会有拷⻉

2. 有返回值,且建议写成当前类类型引⽤,引⽤返回可以提⾼效率,有返回值⽬的是为了⽀持连续赋 值场景。

3. 没有显式实现时,编译器会⾃动⽣成⼀个默认赋值运算符重载,默认赋值运算符重载⾏为跟默认拷 ⻉构造函数类似,对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义 类型成员变量会调⽤他的赋值重载函数

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	Date(const Date& d)//拷贝构造
	{
		cout << "Date(const Date& d)" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	Date operator=(const Date& d)//赋值重载
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}

		return *this;
	}

	~Date()
	{
		cout << "~Date()" << endl;
		_year = -1;
		_month = -1;
		_day = -1;
	}

	void Print()
	{
		cout << _year <<"-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

//代码1
Date func()//传值拷贝也是传地址,出作用域不销毁
{
	Date d(2025, 9, 8);
	return d;
}
int main()
{
	Date ref = func();

	ref.Print();

	return 0;
}//正常打印
//代码二
Date& func()//使用引用出作用域就销毁了,返回值为空出现随机值
{
	Date d(2025, 9, 8);
	return d;//
}


int main()
{
	Date& ref = func();//本质相当于ref是d的别名

	ref.Print();

	return 0;
}//打印随机值

总结:返回对象是一个局部对象或者临时对象,出了func函数的作用域,就析构销毁了,那么就不能用引用返回用引用返回会出现风险,因为引用对象在出func函数时就已经销毁了

虽然引用返回可以减少一次拷贝,但是出了函数作用域,返回对象还在,才能用引用返回。

实现日期的加减

//头文件
#include<iostream>
#include<assert.h>

using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);
	void Print();

	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		static int monthArray[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };

		if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		{
			return 29;
		}
		else
		{
			return monthArray[month];
		}
	}

	
	Date& operator+=(int day);
	Date& operator+(int day);
	//Date& operator-=(int day);
private:
	int _year;
	int _month;
	int _day;
};
//实现操作
#include"Study.h"

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
void Date::Print()
{
	cout << _year << "-" << _month << "-" << _day << endl;
}

Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}
	return *this;
}

Date& Date::operator+(int day)
{
	Date tmp = *this;
	tmp += day;

	return tmp;
}

//测试操作
#include"study.h"

int main()
{
	Date d1(2025, 9, 8);
	Date d2 = d1.operator+(50);

	d1.Print();
	d2.Print();

	return 0;
}//打印2025-10-28

日期类的实现

//声明文件
#pragma once
#include<iostream>
#include<assert.h>

using namespace std;

class Date
{

	friend ostream& operator<<(ostream& out, const Date& d);//友元函数
	friend istream& operator>>(istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1);

	void Print();
	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);

		static int monthArray[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			return 29;
		}
	}
	bool CheckDate();
      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);


	Date& operator+=(int day);
	Date operator+(int day);
	
	Date& operator-=(int day);
	Date operator-(int day); 

	Date operator++();
	Date operator++(int);

	int operator-(const Date& d);

private:
	int _year;
	int _month;
	int _day;
};

//实现文件
bool Date::CheckDate()
{
	if (_month < 1 || _month>13 || _day<1 || _day>GetMonthDay(_year,_month))
	{
		return false;
	}
	else
	{
		return true;
	}
}
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;

	if (!CheckDate())
	{
		cout << "日期非法" << endl;
	}
}

void Date::Print()
{
	cout << _year << "-" << _month << "-" << _day << endl;
}

bool Date::operator<(const Date& d)
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month < d._month)
		{
			return true;
		}
		else if (_month == d._month)
		{
			return _day < d._day;
		}

		return false;
	}
}
bool Date::operator<=(const Date& d)
{
	return (*this < d && *this == d);
}
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 _year == d._year 
		&& _month == d._month 
		&& _day == d._day;
}
bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}

Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}

	return *this;
}
Date Date::operator+(int day)
{
	Date tmp=*this;
	tmp += day;
	return tmp;
}

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-(int day)
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}
Date Date::operator++()
{
	*this += 1;
	return *this;
}
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

int Date::operator-(const Date& d)
{
	Date max = *this;
	Date min = d;
	int falg = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		int falg = -1;
	}
	int n = 0;
	while (*this != d)
	{
		++min;
		++n;
	}

	return n*falg;  
}

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;

	return out;
}
istream& operator>>(istream& in, Date& d)
{
	cout << "请输入年月日:>" << endl;
	in >> d._year >> d._month >> d._day;
	if (!d.CheckDate())
	{
		cout << "日期错误" << endl;
	}

	return in;
}

//测试文件
#include"study.h"

void Test01()
{
	Date d3(2025, 9, 8);
	Date d4 = d3 - 60;
	d3.Print();
	d4.Print();
}

void Test02()
{
	Date d5(2025, 9, 8);
	Date d6 = d5.operator++(0);
	d5.Print();
	d6.Print();
}

void Test03()
{
	Date d1;
	Date d2;

	cin >> d1 >> d2;
	cout << d1 << d2;
}
void Test04()
{
	Date d1(2025, 9, 8);
	Date d2 = d1 + 50;
	d1.Print();
	d2.Print();
}



int main()
{
	

	//Test01();

	//Test02();

	Test03();

	//Test04();
	return 0;
}

初始化列表

成员显示写初始化列表就按照这个值初始化

成员不显示写就看类中是否有缺省值,若有缺省值就按缺省值初始化,没有缺省值内置类型初始化为随机值或者0,自定义类型调用构造函数

#include<iostream>
using namespace std;

typedef int DateType;

class Stack
{
public:
	Stack(size_t capacity = 4)//不需要传参可以自动生成默认构造,去掉缺省值不具备默认构造
	{
		_array = (DateType*)malloc(sizeof(DateType) * capacity);
		if (_array == NULL)
		{
			perror("malloc 申请空间失败!!!");
			return;
		}
		_capacity = capacity;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DateType* _array;
	int _capacity;
	int _size;
};

//class MyQueue
//{
//public:
//	MyQueue(int n, int& rr)//MyQueue也不具备默认构造
//		:_pushst(n)//使用初始化列表:本质可以理解为每个对象定义的地方
//		,_popst(n)//所有成员可以在初始化列表初始化,也可以在函数体内初始化
//		,_size(0)
//		, _x(1)//1.引用 2.const 3.没有默认构造自定义类型成员
//		,_ret(rr)
//	{ }
//private:
//	Stack _pushst;
//	Stack _popst;
//	int _size;
//
//	const int _x;
//
//	int& _ret;
//};
//
//int main()
//{
//	int xx = 0;
//	MyQueue q1(10, xx);
// const int y=1;
// int &ry=xx;
//	return 0;
//}

class MyQueue
{
public:
	MyQueue()//初始化列表,不管写不写,每个成员变量都会走一遍
		//自定义类型成员会调用默认构造函数(没有默认构造会编译报错)Stack(size_t capacity=4)
		//内置类型有缺省值用缺省值,没有的话,看编译器
		//先走初始化列表+再走函数体
		//实践中:尽可能用初始化列表初始化,不方便再用函数体
		:_size(1)
		,_ptr((int*)malloc(40))
	{ }
private:
	Stack _pushst;
	Stack _popst;

	//缺省值  给初始化列表用
	int _size = 0;
	const int _x = 10;
	int* _ptr;
};
//int main()
//{
//	MyQueue q;
//
//	return 0;
//
//
//}
class A
{
public:
	A(int a)
		:_a1(a)
		,_a2(_a1)//先初始化_a2因为a1未初始化所以a2是随机值
	{ }

	void Print()
	{
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2;//声明和初始化必须一致
	int _a1;
};

int main()
{
	A aa(1);
	aa.Print();
	return 0;
}

友元

友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类 声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯

class Time
{
	//Date是Time的友元
	//Date中可以访问Time的私有变量
	//Time不可以访问Date的私有变量
	friend class Date;
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		:_hour(hour)
		,_minute(minute)
		,_second(second)
	{ }

private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		_t._hour++;
	}
private:
	int _year;
	int _month;
	int _day;

	Time _t;
};

内部类

class A
{
private:
	static int k;
	int h;
public:
	void func()
	{ }
private:
	//内部类
	//独立的类,放到A里面
	//仅仅受到类域的限制
	class B//B天生是A的友元
	{
	public:
		void foo(const A& a)
		{
			cout << k << endl;
			cout << a.h << endl;
		}
	private:
		int _b;
	};
};

int main()
{
	cout << sizeof(A) << endl;
	A a1;
	return 0;
}

隐式类型·转换

class A
{
public:
	A(int a)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}

	A(int a1, int a2)
		:_a(0)
		,_a1(_a)
		,_a2(a1)
	{ }

	A(const A& aa)
		:_a(aa._a)
	{
		cout << "A(const A& aa)" << endl;
	}
private:
	int _a;
	int _a1;
	int _a2;
};

int main()
{

	A aa(1);
	//拷贝构造
	A aa2(aa);

	A aa3 = 3;//隐式类型转换
	const A& raa = 3;

	return 0;
}

匿名对象

⽤类型(实参)定义出来的对象叫做匿名对象,相⽐之前我们定义的 类型对象名(实参)定义出来的 叫有名对象 

匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};

class Solution {
public:
	int Sum_Solution(int n)
	{
		//...
		return n;
	}
};

int main()
{
	//A aa1();//不能这样定义因为分不清是类成员还是函数调用
	A();
	A(1);//匿名对象不用起名字,但作用域就这一行

	A aa1(1);
	A aa2(2);
     

	Solution().Sum_Solution(10);//匿名对象使用
	return 0;
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐