C++中的小tip

静态存储区或常量区的字符串都是只读的

char *ap="hello" 声明了一个字符指针 ap,并将字符串 "hello" 的首地址赋值给它。

char ap[]="hello" 声明了一个字符数组 ap,并将字符串 "hello" 的内容复制到数组中。这意味着 ap 是一个数组对象,它包含了字符串 "hello" 的所有字符,包括结尾的空字符 '\0'

c++面对对象的三大特性

是封装、继承、多态

mianxiangduixiang

  1. 算术运算中的隐式转换

:当不同类型的数进行算术运算时,较低精度的类型会转换为较高精度的类型,以便统一运算类型。例如,int和short会转换为int,float会转换为double等。

空类对象所占的内存空间数是1字节

对象的构造和析构的顺序:对象的构造是按照定义对象的顺序依次进行的:对象析构的顺序是按照:先构造后析构,后够早的先析构的原则进行析构的

浅拷贝

浅拷贝的概念

浅拷贝是一种对象复制方式,它将源对象的直接成员变量(包括基本数据类型和指针)复制到新对象中。如果源对象的成员变量是指针,浅拷贝仅仅复制指针本身,而不复制指针所指向的内存区域。因此,源对象和目标对象共享同一块内存空间。

浅拷贝可能导致的问题

当浅拷贝涉及到指针成员时,如果源对象和目标对象的生命周期不同步,或者在某个生命周期结束时释放了指针所指向的内存,那么当目标对象尝试访问这块内存时,就会遇到悬空指针问题。更严重的是,如果两个对象同时释放同一块内存,会导致重复释放错误,这通常会引起程序崩溃。

浅拷贝造成重复释放的原因

浅拷贝造成重复释放的原因在于,当两个对象的生命周期结束时,它们都会尝试释放同一块动态分配的内存。由于浅拷贝使得两个对象持有相同的指针值,这种情况就不可避免地发生了。例如,如果一个对象在其析构函数中释放了指针所指向的内存,然后另一个对象在其析构函数中也尝试释放同一块内存,就会出现重复释放,违反了内存管理的基本原则。

为了避免这些问题,通常需要实现深拷贝(Deep Copy),它不仅复制指针本身,还复制指针所指向的内存内容,确保每个对象拥有独立的副本,从而避免共享状态和潜在的错误. 

深拷贝

自己实现拷贝函数

空类占用内存空间为1

是为了区分空类的位置

friend ostream& operator<<(ostream& os, const Date& date); // 声明友元函数,用于输出Date对象 }; ostream& operator<<(ostream& os, const Date& date) // 实现友元函数,用于输出Date对象 { os << date.m_Year << "年" << date.m_Month << "月" << date.m_Day << "日"; // 输出日期 return os; // 返回ostream对象 }

重载

在表达式cout 中,cout是一个std::ostream类型的预定义对象,它代表标准输出流(通常是你的终端或控制台)。是C++中的插入运算符,用于将数据写入到流中。当你使用运算符将一个自定义对象(如today,一个Date类的实例)插入流中时,实际上是在调用一个重载版本的operator。

这个重载的operator是在你定义Date类时声明的友元函数:

friend ostream& operator<<(ostream& os, const Date& date);

当你执行cout 时,C++编译器会寻找一个匹配的operator函数,它需要一个std::ostream对象(在这里是cout)作为左操作数,和一个Date类型的对象(在这里是today)作为右操作数。编译器找到了你定义的ostream& operator,并调用了它。

这个函数的定义如下:

ostream& operator<<(ostream& os, const Date& date) { os << date.m_Year << "年" << date.m_Month << "月" << date.m_Day << "日"; return os; }

在这个函数体内,os是一个std::ostream对象的引用,它被用来输出date对象的成员变量m_Year、m_Month和m_Day。通过使用运算符,这些数据被格式化为字符串"2023年4月1日",并被写入到os中。由于os在这里实际上就是cout,所以最终结果就是将这个字符串输出到控制台。

最后的endl;实际上是一个特殊的流操纵符,它导致当前输出流(在这里是cout)完成当前输出缓冲区的写入,并在输出中插入一个换行符,使得下一次输出从新的一行开始。

因此,整个过程是这样的:

  1. 执行cout 时,调用ostream& operator函数。
  2. 在函数体内,将date的成员变量格式化为字符串,并写入os。
  3. 执行endl;,完成输出缓冲,并在控制台插入一个换行符。

这就是为什么cout 可以输出格式化的日期字符串的原因。

成员函数(即方法)并不存储在每个对象的内存中。

在一个类中,数据成员(即类的属性)是存储在对象的内存空间中的。当你创建一个类的实例时,数据成员会占用内存空间,这部分空间是为对象中的每个实例变量分配的。

指针在32位中占4个字节,64位操作系统中占8个字节;

多态虚函数内部构造

在定义了一个虚函数virtual时,class类的内存从1变成了4;是因为类内存储了一个vfptr虚函数表指针指向一个虚函数表,虚函数表里存储的是虚函数的地址

当子类重写父类的虚函数后,子类中的虚函数表的内部会替换成子类的虚函数地址

多态中的虚析构函数是在析构函数前面加一个virtual,作用是为了能释放在子类中开辟的堆区

如果父类析构函数不加virtual,子类中的析构函数不会被调用

结构体和类

C语言中的结构体是数据的集合(室友若干种数据类型构成的)

C++中的结构体和类唯一的

静态多态:重载,模版

动态多态:虚函数

指针

#include &lt;iostream&gt;
using namespace std;

int main()
{
    const int a1 = 7; // 正确,声明一个常整型变量
    int const a2 = 8; // 正确,与上一行相同,这是另一种写法
    int c1 = 9; // 正确,声明一个整型变量
    int c2 = 10; // 正确,声明一个整型变量
    
    const int *d1 = &amp;a1; // 正确,声明一个指向常整型的指针 7
    int const* e1 = &amp;a1; // 正确,与d1相同,这是另一种写法 7
    
    const int *d2 = &amp;c1; // 正确,声明一个指向常整型的指针 9
    int const* e2 = &amp;c1; // 正确,与d2相同,这是另一种写法 9
    e2 = e1; // 正确,指针可以指向另一个同类型的指针 9
    
    // *e2 = 33; // 错误,指向常量的指针不能修改所指向的值
    
    int * const f1 = &amp;c1; // 正确,声明一个指向整型的常指针 9
    int * const f2 = &amp;c2; // 正确,声明一个指向整型的常指针 10
    // int * const f3 = &amp;a1; // 错误,常整型的地址不能赋给非常量指针常量
    
    // f2 = f1; // 错误,常指针不能改变所指向的地址
    
    // *f2 = 33; // 错误,常指针指向的值不能修改
    
    const int * const g1 = &amp;a2; // 正确,声明一个指向常整型的常指针 8
    const int * const g2 = &amp;c2; // 正确,声明一个指向常整型的常指针 10
    // g2 = g1; // 错误,常指针不能改变所指向的地址
    
    // *g2 = 33; // 错误,常指针指向的常量值不能修改
    
    *f1 = *g1; // 正确,非常量指针可以修改指向的值 8
    
    
    cout &lt;&lt; "a1=" &lt;&lt; a1 &lt;&lt; ",a2=" &lt;&lt; a2 &lt;&lt; ",c1=" &lt;&lt; c1 &lt;&lt; ",c2=" &lt;&lt; c2 &lt;&lt; endl;
    cout &lt;&lt; "d1=" &lt;&lt; *d1 &lt;&lt; ",d2=" &lt;&lt; *d2 &lt;&lt; endl;
    cout &lt;&lt; "e1=" &lt;&lt; *e1 &lt;&lt; ",e2=" &lt;&lt; *e2 &lt;&lt; endl;
    cout &lt;&lt; "f1=" &lt;&lt; *f1 &lt;&lt; ",f2=" &lt;&lt; *f2 &lt;&lt; endl;
    cout &lt;&lt; "g1=" &lt;&lt; *g1 &lt;&lt; ",g2=" &lt;&lt; *g2 &lt;&lt; endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值