C++ : 四、面向对象编程(2)

(一)对象的生存期

1.对于局部定义的对象,当程序控制流到达该对象定义处时,调用构造函数,程序控制走出该局部域时,调用析构函数。

2.对于静态局部定义的对象,当程序控制流到达该对象定义处时,调用构造函数,整个程序结束时时,调用析构函数。

void fun()
{
	Complex c1(11, 12);
	static Complex sc2(23, 34);
}

3.对全局定义的对象,在进入主程序前就全部定义完成,调用构造函数,整个程序结束时调用析构函数。

class Int
{
private:
	int val;
public:
	Int()//都带有this指针 无返回类型,有返回值,返回值就是它自己
	{
		val = 0;
		cout << "call Int()" << endl;
	}
	Int(int x )
	{
		val = x;
		cout << "call Int(int x)" << endl;
	}
	~Int()//无返回类型,有返回值,返回值是地址
	{
		cout << "Desroy" << endl;
	}
}

Int A(11);//所有全局变量在主函数执行前全部构建完成 , 可见性和顺序有关

int main()
{
    //此时A,B已经创建,但B不可见

}

Int B(11);

 4.动态创建的对象,new创建对象,delete释放对象。

(二)从汇编层面理解引用

引用其实是指针的语法糖。在程序编译过程中,在处理引用时,会把引用看成指针常量。

int main()
{
	double val1 = 12.11;
	double& val2 = val1;// double * const val2 = &val1;
	val2 = 66.88;//*val2 = 66.88
	cout << val1 <<" " << val2<<endl;
}

int & fun(int &c)  // 函数的返回值时一个地址

(三)拷贝构造函数

1、概念

拷贝构造函数,是一种特殊的构造函数,它用于通过已存在的对象来初始化新创建的对象。

(其传参必须采用引用,不然会引起无穷递归)

class Int
{
private:
	int val;
public:
	Int()//都带有this指针 无返回类型,有返回值,返回值就是它自己
	{
		val = 0;
		cout << "call Int()" << this<<endl;
	}
	Int(int x )
	{
		val = x;
		cout << "call Int(int x)" <<this<< endl;
	}
	Int(Int& x)
	{
		this->val = x.val;
	}
	~Int()//无返回类型,有返回值,返回值是地址
	{
		cout << "Desroy" << this<<endl;
	}
}

int main()
{
    Int a(10);
    Int b(a);
}

浅拷贝:如果程序员没有显式定义拷贝构造函数,编译器会为我们自动生成一个默认的拷贝构造函数。这个默认的拷贝构造函数会执行成员变量的逐位复制。

深拷贝:其不仅复制对象的成员变量值,还递归地复制其所引用的所有资源。这意味着每个对象都有自己独立的资源副本,确保了对象之间的数据独立性,通常用于包含指针或动态分配内存的对象,以避免资源共享和释放问题。

class MyString
{
private:
	char* str;
public:
	MyString(const char* p = nullptr) :str(nullptr)
	{
		if (nullptr != p)
		{
			int len = strlen(p);
			str = new char[len + 1];
			strcpy(str, p);
		}
	}

	~MyString()
	{
		delete[]str;
		str = nullptr;
	}

	void PrintString() const
	{
		if (nullptr != str)
		{
			cout << "str: " << str << endl;
		}
	}

	//深拷贝
	MyString(const MyString &s)
	{
		if (s.str == nullptr)
		{
			this->str = nullptr;
		}
		int len = strlen(s.str)+1;
		char* p = new char[len];
		strcpy(p, s.str);
		this->str = p;
	}

	MyString& operator=(const MyString &s)
	{
		if (this == &s)
		{
			return *this;
		}

		delete []this->str;
		this->str = nullptr;

		if (s.str == nullptr)
		{
			return *this;
		}

		size_t len=strlen(s.str)+1;
		char* p = new char[len];
		strcpy(p, s.str);
		this->str = p;
		return *this;

	}
	
};


int main()
{
	MyString s1("yhping");
	MyString s2("hello");
	const char* p = "yuanmeiting";
	MyString s3(s1);
	s1.PrintString();
	s3.PrintString();// yhping;

	s1 = s2;
	s2.PrintString();

 

 如果上述代码不采用深拷贝,会导致两个对象指向同一个堆区new出来的空间,在析构时会引发问题。

2.使用

除了上述的使用外,拷贝构造函数还有两个用处:

(1)作为形参

class Complex
{
	int m_real; //实部
	int m_image; //虚部   int image_; // int m_image;
public:
	Complex() : m_image(0), m_real(0) {}
	Complex(int real, int image) : m_image(image), m_real(real) {}
	~Complex(){}


	Complex Add(const Complex &com) const
	{
		Complex c1;
		c1.m_real = 0;
		return Complex(this->m_real + com.m_real, this->m_image + com.m_image);
	}

};

 此时系统调用Add函数时,不必再为形参开辟新空间。

(2)作为函数返回类型

int& get() 
{
    static int x = 10;  // 静态变量,保证在函数返回后仍然有效
    return x;
}

int main() {
    int& ref = get();  // 获取引用
    cout << "Initial value: " << ref << endl;  // 输出初始值
    ref = 20;  // 修改引用的值
    cout << "Modified value: " << ref << endl;  // 输出修改后的值
    return 0;
}

在使用时,必须要注意返回对象的生存期,不能随着此函数结束而消失。

(四)运算符的重载 

运算符重载是指赋予已有的运算符多重含义。通过运算符重载,程序员可以定义或修改运算符的行为,以便它们能够与用户定义的类型一起使用。

关键字为 operator,它与重载运算符一起构成函数名,因函数名的特殊性,C++编译器可以将这类函数识别出来。

class Int
{
private:
	int val;
public:
	Int()//都带有this指针 无返回类型,有返回值,返回值就是它自己
	{
		val = 0;
		cout << "call Int()" << this<<endl;
	}
	Int(int x )
	{
		val = x;
		cout << "call Int(int x)" <<this<< endl;
	}
	Int(Int& x)
	{
		this->val = x.val;
	}
	~Int()//无返回类型,有返回值,返回值是地址
	{
		cout << "Desroy" << this<<endl;
	}

	void SetVal(int x) // 在编译时会改写为:void SetVal(Int * const this , int x)   
	{
		this->val = x;        //this->val = x;
	}

	int GetVal() const// int GetVal(const Int * const this )  会使对象的成员受const的影响
	{
		return val;
	}

	Int operator+(const Int &Val) const
	{
		
		return Int (this->val + Val.val);
	}
	
	
	Int& operator=(const Int& x) 
	{
		if (this != &x) 
		{ 
			this->val = x.val; 
		}
		
		return *this;
		
	}

	Int &operator++()//前置++
	{
		this->val += 1;
		return *this;
	}
	
	Int operator++(int)//后置++
	{
		/*Int tmp(this->val);
		this->val += 1;
		return tmp;*/
		return Int(this->val++);
		
	}

};

static Int operator+(const int& y, const Int& z)
{
	return z+y;
}

int main()
{
	Int  a(10), b(20);
	Int c(0);

	

	c =a+b;
	cout << c.GetVal() << endl;

	c = a;
	cout << c.GetVal() << endl;
	c = c;
	c = a = b;
	cout << c.GetVal() << endl;




	c = a++;
	cout << c.GetVal() << endl;
	cout << a.GetVal() << endl;


	

}

注意事项: 

1.必须至少有一个操作数是用户定义的类型

2.不能违反运算符原来的规则

3.不能创建新运算符

4.有一些运算符是禁止重载的:sizeof、成员指针运算符(*)、作用域解析运算符(::)、条件运算符(?)等

5.部分运算符只能通过成员函数重载:=:赋值运算符   (): 函数调用运算符 []: 下标运算符 ->: 箭头符号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值