cpp primer plus笔记09-类

  1. 重载运算符的定义:
	#define _CRT_SECURE_NO_WARNINGS 1
#include<cmath>
#include<iostream>
#include<fstream>
namespace Vector3Calculate
{
	class Vector3
	{
	private:
		double x{};
		double y{};
		double z{};
		std::string str;
		const double marginOfEnd = 1e-9;
	public:
		enum class VectorRotation : long int { VectorX, VectorY, VectorZ };
		Vector3(double VectorX = 0, double VectorY = 0, double VectorZ = 0)
			:x(VectorX), y(VectorY), z(VectorZ) {};
		const double GetVector(VectorRotation rotat)
		{
			switch (rotat)
			{
			case Vector3::VectorRotation::VectorX:
				return this->x;
				break;
			case Vector3::VectorRotation::VectorY:
				return this->y;
				break;
			case Vector3::VectorRotation::VectorZ:
				return this->z;
				break;
			default:
				break;
			}
			return 0;
		}
		//this+vect
		const Vector3 operator+(const Vector3& vect) const
		{
			return Vector3(vect.x + this->x, vect.y + this->y, vect.z + this->z);
		}
		//this-vect
		const Vector3 operator-(const Vector3& vect) const
		{
			return Vector3(vect.x - this->x, vect.y - this->y, vect.z - this->z);
		}
		//this*rect
		const Vector3 operator*(const Vector3& vect) const
		{
			return Vector3(vect.x * this->x, vect.y * this->y, vect.z * this->z);
		}
		//this/vect;
		const Vector3 operator/(const Vector3& vect) const
		{
			return Vector3(vect.x / this->x, vect.y / this->y, vect.z / this->z);
		}
		//this=vect
		Vector3 operator=(const Vector3& vect)
		{
			this->x = vect.x;
			this->y = vect.y;
			this->z = vect.z;
			return *this;
		}
		//this+=vect
		Vector3& operator+=(const Vector3& vect)
		{
			this->x += vect.x;
			this->y += vect.y;
			this->z += vect.z;
			return *this;
		}
		//this-=vect
		Vector3 operator-=(const Vector3& vect)
		{
			this->x -= vect.x;
			this->y -= vect.y;
			this->z -= vect.z;
			return *this;
		}
		//this==vect
		bool operator==(const Vector3& vect) const
		{
			if (abs(vect.x - this->x) >= marginOfEnd) return false;
			else if (abs(vect.y - this->y) >= marginOfEnd) return false;
			else if (abs(vect.z - this->z) >= marginOfEnd) return false;
			else return true;
		}
		//this!=vect
		bool operator!=(const Vector3& vect) const
		{
			if (abs(vect.x - this->x) >= marginOfEnd) return true;
			else if (abs(vect.y - this->y) >= marginOfEnd) return true;
			else if (abs(vect.z - this->z) >= marginOfEnd) return true;
			else return false;
		}
		//++this
		Vector3& operator++()
		{
			++this->x;
			++this->y;
			++this->z;
			return *this;
		}
		//this++
		const Vector3 operator++(int)
		{
			return Vector3(this->x++, this->y++, this->z++);
		}
		//--this
		Vector3& operator--()
		{
			--this->x;
			--this->y;
			--this->z;
			return *this;
		}
		//this--
		const Vector3 operator--(int)
		{
			return Vector3(this->x--, this->y--, this->z--);
		}
		//cout<<this
		friend std::ostream& operator<<(std::ostream& cout, const Vector3& vect)
		{
			cout << "Vector3(" << vect.x << "," << vect.y << "," << vect.z << ")";
			return cout;
		}
		//cin>>this;
		friend std::istream& operator>>(std::istream& cin, Vector3& vect)
		{
			cin >> vect.x >> vect.y >> vect.z;
			return cin;
		}
		char& operator[](std::size_t n)//可修改
		{
			return str[n];
		}
		//const char& operator[](std::size_t n) const//不可修改
		//{
		//	return str[n];
		//}
		std::string& operator*() 
		{
			return str;
		}
		std::string* operator->()
		{
			return &this->operator*();
		}
		void operator()(std::string str1, std::string str2)
		{
			std::cout << str1 + str2 << std::endl;
		}
	};
}
int main()
{
	using Vector3Calculate::Vector3;
	Vector3 vect1{ 1,2,3 }, vect2 = Vector3(4, 5, 6);
	std::cout << vect1.GetVector(Vector3::VectorRotation::VectorX) << std::endl;
	std::cout << vect1.GetVector(Vector3::VectorRotation::VectorY) << std::endl;
	std::cout << vect1.GetVector(Vector3::VectorRotation::VectorZ) << std::endl;
	std::cout << vect1 + vect2 << std::endl;
	std::cout << vect1 - vect2 << std::endl;
	std::cout << vect1 * vect2 << std::endl;
	std::cout << vect1 / vect2 << std::endl;
	Vector3 vect3 = vect1;
	std::cout << vect3 << std::endl;
	vect3 += vect2;
	std::cout << vect3 << std::endl;
	vect3 -= vect2;
	std::cout << vect3 << std::endl;
	std::cout << (vect1 != vect3) << " " << (vect1 == vect3) << std::endl;
	std::cout << (vect1++) << " " << vect1 << " " << (++vect1) << " " << vect1 << std::endl;
	std::cout << (vect1--) << " " << vect1 << " " << (--vect1) << " " << vect1 << std::endl;
	vect1("werw", "werwer");//注伪函数时通过对象调用,而不是对象所对应的类类型
	return 0;
}

1
2
3
Vector3(5,7,9)
Vector3(3,3,3)
Vector3(4,10,18)
Vector3(4,2.5,2)
Vector3(1,2,3)
Vector3(5,7,9)
Vector3(1,2,3)
0 1
Vector3(2,3,4) Vector3(3,4,5) Vector3(3,4,5) Vector3(3,4,5)
Vector3(2,3,4) Vector3(1,2,3) Vector3(1,2,3) Vector3(1,2,3)
werwwerwer
  1. 友元有以下三种:
    • 友元函数/运算符。
    • 友元类。
    • 友元成员函数。
  2. 类中函数如果不想更改this指向的数据,可以在函数原型末尾加上const,如int func(int a) const
  3. CPP提供转换函数用于类和其他数据进行有效的转换
    • explicit关键字能够有效防止函数传参的时候进行隐式类型转换,这使得使用转换函数必须要强制显式类型转换。
    • 重载运算符类里面声明后,在类的外部定义不需要加this,可直接引用私有数据成员。
    #include<cmath>
    #include<iostream>
    #include<fstream>
    namespace VectorCalculate
    {
    	class Vector2;
    	class Vector3;
    	class Vector2
    	{
    	private:
    		double x{};
    		double y{};
    	public:
    		enum class Vector2Rotation : unsigned int { VectorX, VectorY };
    		Vector2(double VectorX = 0, double VectorY = 0) :x(VectorX), y(VectorY) {};
    		const double GetVector(Vector2Rotation rotat)
    		{
    			switch (rotat)
    			{
    			case Vector2::Vector2Rotation::VectorX:
    				return this->x;
    				break;
    			case Vector2::Vector2Rotation::VectorY:
    				return this->y;
    				break;
    			default:
    				break;
    			}
    			return 0;
    		}
    		explicit operator Vector3() const;
    		friend std::ostream& operator<<(std::ostream& fout, const Vector2& vect2)
    		{
    			fout << "(" << vect2.x << ", " << vect2.y << ")";
    			return fout;
    		}
    	};
    	class Vector3
    	{
    	private:
    		double x{};
    		double y{};
    		double z{};
    	public:
    		friend class Vector2;
    		enum class Vector3Rotation : long int { VectorX, VectorY, VectorZ };
    		Vector3(double VectorX = 0, double VectorY = 0, double VectorZ = 0)
    			:x(VectorX), y(VectorY), z(VectorZ) {};
    		const double GetVector(Vector3Rotation rotat)
    		{
    			switch (rotat)
    			{
    			case Vector3::Vector3Rotation::VectorX:
    				return this->x;
    				break;
    			case Vector3::Vector3Rotation::VectorY:
    				return this->y;
    				break;
    			case Vector3::Vector3Rotation::VectorZ:
    				return this->z;
    				break;
    			default:
    				break;
    			}
    			return 0;
    		}
    		explicit operator Vector2() const
    		{
    			return Vector2(this->x, this->y);
    		}
    		friend std::ostream& operator<<(std::ostream& fout, const Vector3& vect3)
    		{
    			fout << "(" << vect3.x << ", " << vect3.y << ", " << vect3.z << ")";
    			return fout;
    		}
    	};
    	Vector2::operator Vector3() const
    	{
    		return Vector3(x, y, 0.0);
    	};
    }
    int main()
    {
    	using VectorCalculate::Vector2;
    	using VectorCalculate::Vector3;
    	Vector2 vect2 = Vector2(1, 1);
    	Vector3 vect3 = Vector3(2, 3, 4);
    	Vector2 vect4 = (Vector2)vect3;
    	Vector3 vect5 = (Vector3)vect2;
    	std::cout << vect4 << std::endl;
    	std::cout << vect5 << std::endl;
    	return 0;
    }
    
  4. 分析以下代码:
    #include<iostream>
    #include<cstring>
    class StringBad
    {
    private:
    	char* str;
    	int len;
    	static int num_strings;
    public:
    	StringBad(const char* s);
    	StringBad();
    	~StringBad();
    	friend std::ostream& operator<<(std::ostream& os, const StringBad& st);
    };
    int StringBad::num_strings = 0;
    StringBad::StringBad(const char* s)
    {
    	len = std::strlen(s);
    	str = new char[len + 1];
    	std::strcpy(str, s);
    	num_strings++;
    }
    StringBad::StringBad()
    {
    	len = 4;
    	str = new char[4];
    	std::strcpy(str, "C++");
    	num_strings++;
    	std::cout << num_strings << R"(: ")" << str << R"(" object created)" << std::endl;
    }
    StringBad::~StringBad()
    {
    	std::cout << R"(")" << str << R"(" object deleted, )";
    	--num_strings;
    	std::cout << num_strings << " left\n";
    	delete[] str;
    }
    std::ostream& operator<<(std::ostream& os, const StringBad& st)
    {
    	os << st.str;
    	return os;
    }
    
    • 该代码中使用了默认的复制构造函数,当函数按值传递对象或者函数返回对象是,都将使用复制构造函数,复制构造函数将在一下情形使用:

      StringBad motto();//不使用复制构造函数
      StringBad ditto(motto);//使用复制构造函数
      StringBad also=StringBad(motto);//使用复制构造函数
      StringBad * pStringBad = new StringBad(motto);//使用复制构造函数
      

      默认的复制构造函数会逐个复制非静态成员的值,如果成员本身是个类对象,则使用该成员的类的复制构造函数来复制成员对象,而静态成员不受影响。

    • 由于使用了默认复制构造函数,这使得(字符串)数组,赋值的时候使用的是a = b,而不是memcpy或者strcpy,从而会使得赋值变成复制数组地址,从而会使得被赋值的数组出现乱码,当赋值的数据被delete掉时,数组中的指针指向的数据会被delete掉,从而使得如果被赋值数据被delete掉时,会delete数据数据两次,引发异常。

    • 由于使用两次默认复制构造函数,而且没有给num_string赋值,这使得num_string在最后一次析构函数调用时变成-2.

    • 如果不是在第一次初始化时使用a = b,会调用默认的赋值运算符,从而再次导致以上特征,因此需要重载赋值运算符,需要注意一下条件:

      1. 由于目标对象可能引用了以前分配的数据,所以函数需要使用delete[]或者delete释放这些数据。
      2. 函数避免将对象给自身赋值,否则给对象重新赋值前,释放内存操作可能删除对象的内容。
      3. 函数返回一个指向调用对象的引用。
    StringBad& StringBad::operator(const StringBad& st)
    {
    	if(this == &st) return *this;//注意2
    	delete[] std;//注意1
    	len=st.len;
    	str=new char[len+1];
    	str::strcpy(str,st.str);
    	return *this;
    }
    
    	#define _CRT_SECURE_NO_WARNINGS 1
    	#include<cstring>
    	#include<iostream>
    	class StringBad
    	{
    	private:
    		char* str;
    		int len;
    		static const int CINLIM = 1e5;
    	public:
    		StringBad(const char* s)
    		{
    			len = std::strlen(s);
    			str = new char[len + 1];
    			std::strcpy(str, s);
    		}
    		StringBad()
    		{
    			len = 0;
    			str = new char[1];
    			str[0] = '\0';
    		}
    		StringBad(const StringBad& st)
    		{
    			len = st.len;
    			str = new char[len + 1];
    			std::strcpy(str, st.str);
    		}
    		StringBad& operator=(const StringBad& st)
    		{
    			if (this == &st) return *this;
    			delete[] str;
    			len = st.len;
    			str = new char[len + 1];
    			std::strcpy(str, st.str);
    			return *this;
    		}
    		~StringBad()
    		{
    			delete[] str;
    		}
    		friend bool operator<(const StringBad& st1, const StringBad& st2)
    		{
    			return (std::strcmp(st1.str, st2.str) < 0);
    		}
    		friend bool operator>(const StringBad& st1, const StringBad& st2)
    		{
    			return st2 < st1;
    		}
    		friend bool operator==(const StringBad& st1, const StringBad& st2)
    		{
    			return (std::strcmp(st1.str, st2.str) == 0);
    		}
    		const char& operator[](int pos) const
    		{
    			return str[pos];
    		}
    		friend std::ostream& operator<<(std::ostream& os, const StringBad& st)
    		{
    			os << st.str;
    			return os;
    		}
    		friend std::istream& operator>>(std::istream& is, StringBad& st)
    		{
    			char temp[StringBad::CINLIM];
    			is.get(temp, StringBad::CINLIM);
    			if (is) st = temp;
    			while (is && is.get()!='\n')
    			{
    				continue;
    			}
    			return is;
    		}
    		static const int GetCINLIM()
    		{
    			return CINLIM;
    		}
    	};
    	int main()
    	{
    		return 0;
    	}
    
    
  5. 在类中使用new应该要注意:
    • 如果在构造函数中使用new初始化成员,应在析构函数中使用delete。
    • 如果有多个构造函数,则必须以相同的方式使用new,要么都带[],要么都不带。因为只有一个析构函数,所有构造函数都必须与它兼容,但是可以在一个构造函数中使用new初始化指针,并且在另一个构造函数将指针初始化为空。
    • 应该定义一个复制构造函数,通过深度复制将一个对象初始化为另一个对象。
    • 应该定义一个赋值运算符,通过深度复制将一个对象复制给另一个对象。
  6. 使用定位new运算符初始化类需要注意一下几点:
    • 如果不恰当的选择好分配地址的话,可能会导致向前正在被使用的内存单元被覆盖掉。
    • 如果被分配的内存单元被delete掉,需要在此之前调用析构函数将定位new运算符初始化的数据删除掉。
    char* buffer = new char[512];
    StringBad* pc1, * pc2;
    pc1 = new (buffer) StringBad;
    pc2 = new StringBad("Heap1");
    StringBad* pc3, * pc4;
    //pc3 = new (buffer) StringBad("Bad Idea");//注意点一
    pc3 = new (buffer + sizeof(StringBad))StringBad("Bad Idea");
    pc4 = new StringBad("Heap2");
    delete pc2;
    delete pc4;
    pc3->~StringBad();//注意点二
    pc4->~StringBad();//注意点二
    delete[] buffer;
    
  7. 构造函数初始化列表可用于初始化引用数据成员和非静态const数据成员。
    class StringBad
    {
    private:
    	StringBad& str;
    	const int len = 0;
    public:
    	StringBad(StringBad& String, int length) :str(String), len(length) {};
    };
    
  8. 派生类和基类之间存在以下特殊关系:
    • 基类指针可以在不进行显式类型转换的情况下指向派生类对象,基类引用可以在不进行显式类型转换的情况下引用派生类对象,但是在此情况下的基类指针和引用只能调用基类方法,不能使用派生类的方法。
    • 派生类指针和派生类引用不能隐式被基类对象,引用,地址赋值。
    • 如果一个函数需要传入参数为基类的值,指针或者引用,那么在调用函数的时候,可以传入一个派生类的值,指针或者引用。
    • 如果将派生类的数据给基类初始化或者赋值,这会使得派生类中不是派生类声明的所有数据都会赋值给基类。
    • 尽量不要进行上面所述操作,因为这会使得代码更难更改,如果类型是多态或者涉及资源管理,会更加难改。
    #include<cstring>
    #include<iostream>
    class Base
    {
    private:
    	int a = 0;
    protected:
    	int b = 0;
    public:
    	int c = 0;
    	Base(int baseA, int baseB, int baseC) :a(baseA), b(baseB), c(baseC) {};
    	Base() {};
    	friend std::ostream& operator<<(std::ostream& os, const Base& base)
    	{
    		os << "Base:(" << base.a << ", " << base.b << ", " << base.c << ")";
    		return os;
    	}
    };
    class Son :public Base
    {
    private:
    	int d;
    	void Fun1()
    	{
    		//this->a = 0;
    		this->b = 0;
    		this->c = 0;
    	}
    public:
    	Son(int baseA, int baseB, int baseC, int baseD) :Base(baseA, baseB, baseC), d(baseD) {};
    	Son(const Base& base, int baseD) :Base(base), d(baseD) {};
    	friend std::ostream& operator<<(std::ostream& os, const Son& son)
    	{
    		os << "Son:(" << son.b << ", " << son.c << ", " << son.d << ")";
    		return os;
    	}
    };
    
    int main()
    {
    	Son son1 = Son(1, 2, 3, 4);
    	Base& base1 = son1;
    	Base* base2 = &son1;
    	Base base3 = Son(son1, 2);
    	Base base4 = Son(5, 6, 7, 8);
    	Base base5;
    	base5 = son1;
    	std::cout << son1 << std::endl;
    	std::cout << base1 << std::endl;
    	std::cout << *base2 << std::endl;
    	std::cout << base3 << std::endl;
    	std::cout << base4 << std::endl;
    	std::cout << base5 << std::endl;
    	return 0;
    }
    
    Son:(2, 3, 4)
    Base:(1, 2, 3)
    Base:(1, 2, 3)
    Base:(1, 2, 3)
    Base:(5, 6, 7)
    Base:(1, 2, 3)
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值