- 重载运算符的定义:
#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
- 友元有以下三种:
- 友元函数/运算符。
- 友元类。
- 友元成员函数。
- 类中函数如果不想更改this指向的数据,可以在函数原型末尾加上const,如int func(int a) const
- 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; }
- 分析以下代码:
#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,会调用默认的赋值运算符,从而再次导致以上特征,因此需要重载赋值运算符,需要注意一下条件:
- 由于目标对象可能引用了以前分配的数据,所以函数需要使用delete[]或者delete释放这些数据。
- 函数避免将对象给自身赋值,否则给对象重新赋值前,释放内存操作可能删除对象的内容。
- 函数返回一个指向调用对象的引用。
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; }
-
- 在类中使用new应该要注意:
- 如果在构造函数中使用new初始化成员,应在析构函数中使用delete。
- 如果有多个构造函数,则必须以相同的方式使用new,要么都带[],要么都不带。因为只有一个析构函数,所有构造函数都必须与它兼容,但是可以在一个构造函数中使用new初始化指针,并且在另一个构造函数将指针初始化为空。
- 应该定义一个复制构造函数,通过深度复制将一个对象初始化为另一个对象。
- 应该定义一个赋值运算符,通过深度复制将一个对象复制给另一个对象。
- 使用定位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;
- 构造函数初始化列表可用于初始化引用数据成员和非静态const数据成员。
class StringBad { private: StringBad& str; const int len = 0; public: StringBad(StringBad& String, int length) :str(String), len(length) {}; };
- 派生类和基类之间存在以下特殊关系:
- 基类指针可以在不进行显式类型转换的情况下指向派生类对象,基类引用可以在不进行显式类型转换的情况下引用派生类对象,但是在此情况下的基类指针和引用只能调用基类方法,不能使用派生类的方法。
- 派生类指针和派生类引用不能隐式被基类对象,引用,地址赋值。
- 如果一个函数需要传入参数为基类的值,指针或者引用,那么在调用函数的时候,可以传入一个派生类的值,指针或者引用。
- 如果将派生类的数据给基类初始化或者赋值,这会使得派生类中不是派生类声明的所有数据都会赋值给基类。
- 尽量不要进行上面所述操作,因为这会使得代码更难更改,如果类型是多态或者涉及资源管理,会更加难改。
#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)