C++基础知识学习——2

1、类的初始化

class A
{
public:

	//1.在构造函数体内初始化
	/*
	A(int a, int b)
	{
		//  成员变量a 与 b 这里并没有被赋值,因为这里的a,b全部都是形参,把成员变量隐藏了
		a = a;
		b = b;
		cout << "自定义有参构造函数!" << endl;
	}

	//解决方法一: 形参与成员变量名不同即可
	A(int a1, int b1)
	{
		a = a1;
		b = b1;
		cout << "自定义有参构造函数!" << endl;
	}
	
	//解决方法二: 使用this指针
	A(int a, int b)
	{
		this->a = a;//明确的指出是对象自己的a、b
		this->b = b;
		cout << "自定义有参构造函数!" << endl;
	}
	*/

	//2.使用初始化列表进行成员变量的初始化
	A(int a, int b) : a(a), b(b)
	{ 
		cout << "自定义有参构造函数!" << endl;
	}
	 
	void print()
	{
		cout << a << "   " << b << endl;
	}

private:
	int a; //按照此处的定义顺序初始化
	int b; 
};

这两种方式,对基本类型成员无区别的,但对复杂类型成员,如类和结构体等,则第二种效率高,因为第一种会调用一次默认的构造函数,在类构造函数里又会调用一次成员的构造函数再赋值,而第二种仅在初始化列表里调用一次成员的构造函数并赋值。

:以下情况必须使用初始化列表:

  1. 在派生类中构造函数中初始化提供父类的初始化。
  2. 如果成员是常量或引用,成员无法使用赋值的方式,必须在初始化列表中初始化
  3. 成员变量是类的类型

2、常成员变量

常成员变量是一直不变的,不能被赋值的,并且构造函数中只能用初始化列表的方式,其他初始化方法都是非法的。

class A
{
public:
	A(int a): a(a)//初始化列表
	{
		//this->a = a;  //这种写法不能用于 const的成员变量,需用初始化列表
	}

	void print()
	{
		//a = 200;  //成员函数中,无法修改const成员变量
		cout << a << endl;
	}

private:
	const int a;//加上const、常成员变量
};

3、常成员函数

如果只想对对象进行读操作,则成员函数可以设计成常成员函数,在常成员函数中只能读取,而不能修改成员变量的值。

class B
{
public:
	B(int b)  
	{
		this->b = b; 
	}

	//希望print中无法改变任何成员变量的值,则把他声明为常成员函数
	void print() const
	{
		//this->b = 200;  不能进行任何修改成员变量的值,哪怕b可以修改
		cout << this->b << endl;
	}

	//普通成员函数
	void print2()  
	{
		this->b = 200;
		cout << this->b << endl;
	}

private:
	int b; 
};

4、mutable

在C++中,mutable是为了突破const的限制而设置的。被mutable修饰的变量,将永远可变,即使在一个const函数中。

class  B
{
public:
	B(int b)
	{
		this->b = b;
	}

	void print() const
	{
		//this->a = 100;//不可以,在常成员函数中,无法修改
		this->b = 200; //加上了mutable,使得在常成员函数中变成例外
		cout << this->b << endl;
	}
	  
private:
	int a;
	mutable int b;
};

5、常对象

常对象保护了对象中所有的数据成员不能被任何函数访问和修改,只能使用常成员函数来访问。

class A
{
public:
	A(int a)
	{
		this->a = a;
	}
	//普通成员函数
	void print1()
	{
		this->a = 200;
		cout << this->a << endl;
	}

	//常成员函数
	void print2() const
	{
		//this->a = 200;//常成员函数中不可修改任何成员变量的值
		cout << this->a << endl;
	}

private:
	int a;
};

int  main()
{
	const A a(111);// a是常对象,只能调用常成员函数
	a.print2();
	//a.print1();//不能调用非常成员函数
	return 0;
}

6、拷贝构造函数

拷贝构造函数也是一种构造函数。它用同类型的对象来初始化新创建的对象。其唯一的形参是 const 类型 & ,此函数也由系统自动调用。
注:拷贝构造函数可以理解为就是构造函数的一种重载。

class A
{
public:
	A(int a)
	{
		this->a = a;
		cout << "调用构造函数!" << endl;
	}

	//固定写法,可以认为是构造函数的重载
	A(const A & tmp)
	{
		this->a = tmp.a;
		cout << "调用拷贝构造函数!" << endl;
	}

	void print()
	{
		cout << a << endl;
	}

private:
	int a;
};


int  main()
{
	A tmp1(111);	//调用有参的构造函数
	A tmp2(tmp1);	//定义的时候用对象初始化,调用拷贝构造函数
	A tmp3 = tmp1;	//定义的时候用对象初始化,调用拷贝构造函数
 
	//三个对象的成员变量a的值一样
	tmp1.print();
	tmp2.print();
	tmp3.print();

	return 0;
}

7、浅拷贝和深拷贝

浅拷贝只是简单的值拷贝,而深拷贝做的工作要更多
注:默认的拷贝构造函数是浅拷贝

class A
{
public:
	A(char *str)
	{
		int len = strlen(str) + 1;
		p = new char[len];
		memcpy(p, str, len);
	}

	void print()
	{
		cout << p << endl;
	}

	//自定义的拷贝构造函数- 深拷贝
	A(const A & tmp)
	{
		int len = strlen(tmp.p) + 1;
		p = new char[len];
		memcpy(p, tmp.p, len);
	}

	char *p; //指针变量 
};

int main()
{
	A a("hello");
	a.print();

	//浅拷贝:调用默认的拷贝构造函数,仅仅值拷贝,相当于 b.p= a.p;
	//深拷贝:使用自定义的拷贝构造函数,相当于进行了内存的拷贝
	A b(a);
	b.print();

	strcpy(a.p, "world");
	a.print();
	b.print();

	return 0;
}

8、析构函数

析构函数与构造函数相反,它是特殊的类成员函数,它没有返回值、参数,无法重载,在类的生命期结束的时候,被系统自动调用。

class A
{
public: 
	A(int a)
	{
		this->a = a;
		cout << this->a << " 自定义默认的构造函数!" << endl;
	}

	~A()
	{
		//做清理扫尾工作
		cout << this->a << "自定义的析构函数!" << endl;
	}

private:
	int a;
};


int main()
{
	// 栈区
	A a(1);	//a创建的时候构造,销毁的时候析构
	
	// 堆区
	A *p = new A(2);//调用构造函数
	delete p;//调用析构函数
	
	return 0;
}

9、运算符重载

1)基本的运算符重载:
类型 operator 运算符 (形参表)
{
函数体;
}

class A
{
public:
	A(int a)
	{
		this->a = a;
		cout << "调用自定义构造函数!" << endl;
	}

	//运算符重载
	A operator + (const A & tmp)
	{
		return A(this->a + tmp.a);
	}

	void print()
	{
		cout << a << endl;
	}

private:
	int  a;
};


int main()
{
	A a(111);	// 调用有参构造函数
	A b(222);	// 调用有参构造函数

	// +号运算符重载
	A c = a + b;// 调用有参构造函数
	c.print();

	return 0;
}

2)赋值运算符重载函数(=):
也是一种特殊的成员函数。它用于对象之间的赋值。它本质上是重载类的“=”赋值操作符。
注:赋值运算符重载函数与靠背构造函数不同,后者是定义时触发。

class A
{
public:
	A(int a)
	{
		this->a = a;
		cout << "调用自定义构造函数!" << endl;
	}

	A(const A & tmp)
	{
		this->a = tmp.a;
		cout << "调用自定义拷贝构造函数!" << endl;
	}

	void print()
	{
		cout << a << endl;
	}

	//自定义=赋值运算符重载函数
	A & operator = (const A &tmp)
	{
		if (this == &tmp)
		{
			return *this;	//直接返回自己
		}
		this->a = tmp.a;	//进行赋值
		cout << "自定义=赋值运算符重载函数" << endl;
		return *this;		//返回对象本身
	}

private:
	int a;
};

int main()
{
	A a(111);	//调用有参的构造函数

	A b(a);		//调用拷贝构造函数 
	A c = a;	//调用拷贝构造函数


	A e(222);	//调用有参的构造函数

	// 如果没有自定义的=运算符重载函数,则调用默认的

	a = e;//没有调用拷贝构造,这个时候,对象没有发生构造,a早就构造好了
	a.print();

	a = a;//自己赋值给自己
	a.print();

	return 0;
}

赋值运算符重载函数与拷贝构造函数的区别:

  1. 拷贝构造函数时定义一个对象时被调用
  2. 赋值运算符重载函数是对一个已经存在的对象进行拷贝赋值(没有新的对象产生)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值