最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

世界快播:C++ class struct

来源:博客园

class and struct

目录

  • 前文
  • 问题
  • 对象与引用
    • 引用的传递
  • 对象 copy
    • shallow copy
    • depthcopy
      • memcpy(data,a.data,sizeof(T) *n);
      • 简单类型
      • 复杂类型
      • 指针类型的拷贝
      • 原位构造
  • 返回值优化 (RVO)
    • 拷贝构造的现象
  • 关键字
    • default
    • delete
  • 函数重载
    • 问题
    • code

前文

c++ 中的class 和struct

struct 默认为 public


(资料图)

class 默认为private

问题

左值引用,右值引用区别?

什么时候需要定值浅拷贝和深拷贝的函数。

传值和传值的区别

对象与引用

引用的传递

返回引用就意味着是data[ind]的別名。

using namespace std;class Vector{public:    Vector(int n =100) : n(n),data(new int[n]){}    int &at(int ind){return data[ind];}private :     int n ;     int *data;};int main(){    Vector arr;    for(int i=0; i< 1; i++){        arr.at(i) = i;                    }       return   0;  }

对象 copy

实际上两种copy是逻辑上的

class Vector{public:    Vector(int n =100) : n(n),data(new int[n]){}    int &at(int ind){        cout << "ind" << ind << endl;        return data[ind];    }       int &operator[](int ind) {return data[ind];}    void output (int m = -1){        if(m == -1)   m = n;            cout <<"Arr"  <<  this << endl;        for(int i = 0; i < m; i++){            cout << data[i] << " ";        }        cout << endl;        return ;    }   private :     int n ;     int *data;};

shallow copy

int main(){    Vector arr;    for(int i=0; i< 10; i++) arr[i]=i;        arr.output(10);    Vector arr2(arr);    arr2.output(10);    arr2[3]=1000;    arr.output(10);    arr2.output(10);     return   0;}   Arr0x7ffcddc92630  arr 0 1 2 3 4 5 6 7 8 9 Arr0x7ffcddc92620 arr 20 1 2 3 4 5 6 7 8 9 Arr0x7ffcddc926300 1 2 1000 4 5 6 7 8 9 Arr0x7ffcddc926200 1 2 1000 4 5 6 7 8 9   arr  {n=100 data=0x000002196c4ad400 {0} }  Vector  arr2 {n=100 data=0x000002196c4ad400 {0} }  Vector  vs 的debug 模式下 data

本代码将arr 拷贝给了arr2 ,本身属于两个不同的对象。

既然属于不同的对象,arr2的变动不应对arr1发生改变,但是事与愿违 ,因为受拷贝行为的影响,依次性的拷贝,由于是指针域,拷贝了同一个存储区的值。所以 arr2 发生更改,arr1 也会发生更改。

☕如果copy 的对象是指针类型时,这个方式就无法适用了.

depthcopy

指针类型并非是赋值关系,存arr2 应该是一个额外的存储区。

memcpy(data,a.data,sizeof(T) *n);

当前方法在一定的简单类型的场景下可以进行深拷贝,如果类型中存在了指针类型则也会出现两个指针指向同一个地址的的情况。

#include                                                                       #include#include#includeusing namespace std;#define  BEGINS(x) namespace x {//begin of namespace #define  ENDS(x)} //end of namespace x BEGINS(xxx)class A  {    public :                                                                                     int x , y;};ostream &operator<<(ostream &out ,const A &a){    out <<  "(" << a.x <<   " , " << a.y << ")";    return out;}templateclass Vector{                                                                            public:    Vector(int n =100) : n(n),data(new T[n]){}    Vector (const Vector &a): n(a.n){        // 实现深拷贝        data = new T[n];        /*           for(int i = 0; i < n; i++){           data[i]=a.data[i];           } */        //实现以上的效果        //1 : memcpy 可能是复制类型是复杂类型的对象        memcpy(data,a.data,sizeof(T) *n);        return ;    }    T &at(int ind){        cout << "ind" << ind << endl;        return data[ind];    }    T &operator[](int ind) {return data[ind];}    void output (int m = -1){        if(m == -1)   m = n;            cout << "Arr size " << sizeof(data) << " "  <<  this << endl;        for(int i = 0; i < m; i++){            cout << data[i] << " ";        }        cout << endl;        return ;    }private :     int n ;    T *data;};ENDS(xxx)

简单类型

BEGINS(test1)using namespace xxx;     int main(){         Vector  arr;        for(int i=0; i< 10; i++) arr[i]=i;        arr.output(10);        Vector  arr2(arr);        arr2.output(10);                                                                         arr2[3]=1000;        arr.output(10);        arr2.output(10);        return   0;    }ENDS(test1)Arr size 8 0x7ffc86e546d00 1 2 3 4 5 6 7 8 9 Arr size 8 0x7ffc86e546c00 1 2 3 4 5 6 7 8 9 Arr size 8 0x7ffc86e546d00 1 2 3 4 5 6 7 8 9 Arr size 8 0x7ffc86e546c00 1 2 1000 4 5 6 7 8 9

☕由结果可以看到,很显然在copy后并没有影响arr1的指针域

复杂类型

BEGINS(test2)using namespace xxx;                                                                                         int main(){    Vector arr1;    for(int i =  0; i < 10; i++){        arr1[i].x = i;        arr1[i].y = 2 * i;    }       arr1.output(10);    Vector arr2(arr1);    arr2[3] = (A){4, 100};    arr2.output(10);    arr1.output(10);    return 0;}ENDS(test2)Arr size 8 0x7ffc053fdeb0   //原 (0 , 0) (1 , 2) (2 , 4) (3 , 6) (4 , 8) (5 , 10) (6 , 12) (7 , 14) (8 , 16) (9 , 18) Arr size 8 0x7ffc053fdea0    (0 , 0) (1 , 2) (2 , 4) (4 , 100) (4 , 8) (5 , 10) (6 , 12) (7 , 14) (8 , 16) (9 , 18) Arr size 8 0x7ffc053fdeb0(0 , 0) (1 , 2) (2 , 4) (3 , 6) (4 , 8) (5 , 10) (6 , 12) (7 , 14) (8 , 16) (9 , 18) 

☕在不涉及对象中的(指针类型)(其中类型不需要深拷贝的场景)的情况下,可以实现深拷贝。

指针类型的拷贝

memcpy 是无法做到深拷贝的,无法完美的迁移。

BEGINS(test3)using namespace xxx;int main(){   Vector> arr1;   Vector> arr2(arr1);   arr2[2][2]=1000;   for(int i =0; i <3 ; i++){       arr1[i].output(3);       cout <

原位构造

位构造 new (地址),其意思为:在某个地址上调用某个构造函数,构造一个相关的对象

如果数据类型T执行深拷贝的函数,将call T类型的拷贝构造函数

https://hedzr.com/c++/variant/in-place-construction-in-cxx/ 参考文章

Vector(const Vector &a):n(a.n){        //  data = new T[n];//实现深拷贝, 带new 就调用n次构造函数         data =(T *)malloc(sizeof(T) * n);         /* for(int i = 0; i < n; i++){           data[i]=a.data[i];           } */        //1 : memcpy 可能是复制类型是复杂类型的对象        //原位构造 new (地址),其意思为:在某个地址上调用某个构造函数,构造一个相关的对象        for(int i = 0; i < n; i++){            //如果数据类型T执行深拷贝的函数,将call T类型的拷贝构造函数             new (data + i) T(a.data[i]); //这里也调了i次                                             }      // memcpy(data,a.data,sizeof(T) * n);        return ;    }  

返回值优化 (RVO)

对象: 已经经历了构造过程的数据区 。obj (申请对象数据区)→匹配构造函数 →完成构造(某对象)

-fno-elide-constructors 关闭返回值优化

拷贝构造的现象

按照流程应该是发生了三次构造 ? 为什么输出的解构为什么是同一个地址按照正常逻辑, 中间的匿名对象应该没意义的 只是一个中转的功能所以 第一步就吧匿名的临时变量优化掉 第二 ->tmep 拷贝给A对象 ,既然是拷贝他们是一模一样,加在temp对象所有的操作都会在去往A上 temp 对象其实可以看做A对象的别名,这就是返回值优化的最终版本 最终是 吧temp 当做A对象的引用了

#include#include#include#include#include#include#include#include  using namespace std;  class A{public:    A(){        cout << this <<"  default constructor" << endl;    }    A(int x){        cout << this << "  param cpms" << endl;    }    A(const A&a){        cout << "  copy constructor" << endl;    }};  A  func(){    A temp(3);   // 代参数的构造    cout << " temp " <<  &temp << endl;    return temp;// 这里应该是属于匿名变量拷贝给了 A}int main(){    A a =func(); //匿名对象在拷贝A     cout  <<" a :"  << &a <

关键字

隐形的行为,显性化 ,将代码的层面的规则,变成显示的规则

default

不一样点 :如果想要实现拷贝构造必须是初始化列表挨个拷贝, default 关键字会挨个执行拷贝方法

如果是默认的构造函数,他是一个东西

class A{  A() = default;  // 隐性的行为显性化  A(const A &) =default;    A(const A &) {} //这和上面不是一个东西};      

delete

删除后,如果想使用,编译会直接报错。

class A{                                                                           |~                     A() = default;  // 隐性的行为显性化                                              |~                     //A(const A &) =default;                                                         |~                     A(const A &) = delete;                                                           |~                                                                                                      |~                     // A() {} 这和上面不是一个东西                                                   |~                   };                                                                                 |~                            

函数重载

如果一个作用内,函数名称相同,但是参数列表不同,称函数重载 (参数类型不同,参数个数不同(记得默认参数的问题))。

强调一下 和返回值没关系

问题

函数重载 好处?

  1. 有了函数重载,可以吧把一类通过参数区分的功能,命名成一个函数名。(精细化的处理流程)
  2. 通过函数参数的列表对函数进行提示
  3. 对函数进行扩展

code

int func(int x ){    return 2 * x;}double func(double x){     return 2.0 * x;}int ABS(int x ){    return abs(x);}double ABS(double x){     return fabs(x);}int main(){    cout << func(1) << endl;    cout << func(22.0) << endl;        cout <<  ABS(222.56) << endl;    cout << ABS(-233) << endl ;  return 0;}     

关键词: