(一)对象的生存期
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.部分运算符只能通过成员函数重载:=:赋值运算符 (): 函数调用运算符 []: 下标运算符 ->: 箭头符号

被折叠的 条评论
为什么被折叠?



