zoukankan      html  css  js  c++  java
  • 构造函数

    构造函数

    初始化:被初始化的对象正在创建
    赋值:被赋值的对象已经存在

    构造函数为了提供初始化用的,

    构造函数有:默认构造函数,拷贝构造函数

    //    Test2(int a=0, int b=0): m_a(a),m_b(b) {}  推荐这样写
    #include <iostream>
    
    using namespace std;
    // 同一个项目最好不要有相同的类名(防止串包)
    // 默认构造函数:可以写成有参数的并且,形参写上初始值
    class Test2
    {
    public:
        Test2()
        {
            cout << "无参构造函数" << endl;
        }
        Test2(int a)
        {
            m_a = a;
        }
        Test2(int a, int b)  // 调用有参构造函数 3种方法
        {
            m_a = a;
            m_b = b;
            cout << "有参构造函数" << endl;
        }
        // 赋值构造函数(拷贝构造函数)
        Test2(const Test2 & t2)
        {
            cout << "拷贝构造函数" << endl;
        }
    
        ~Test2()
        {
    
        }
        void printT()
        {
            cout << "普通成员函数" << endl;
        }
    private:
        int m_a;
        int m_b;
    };
    // 调用有参构造函数 三种方法 第一种比较常用
    int main()
    {
        // Test2 t1;  // 调用无参构造函数
        // Test2 t1();  // 调用有参构造函数(编译能通过,使用的时候回报错)
    
        // 1 括号法
        Test2 t1(1, 2);   // c++编译器帮我们调用构造函数(t1和t2都是)
        t1.printT();
    
        // 2 = 号法
        // t2不建议使用
        Test2 t2 = (1, 2, 3, 4);  // 报错因为没有一个参数的构造函数,如果有的话就会调用一个的把4用来初始化
        Test2 t3 = 5;  // 调用一个参数的构造函数
    
        // 3直接调用构造函数  手动调用
        // 调用一次后面的然后转成t4
        Test2 t4 = Test2(1, 2);  // 匿名对象(匿名对象的去和留)抛砖。t4对象初始化
    
        t1 = t4; // 把t4拷贝给t1 拷贝构造函数
    // 对象的初始化和对象的赋值是两个概念
        return 0;
    }
    简单分类

    拷贝构造函数调用的时机

    拷贝构造函数调用时机
    将一个对象作为实参传递给一个非引用类型的形参
    从一个返回类型为非引用的函数返回一个对象(匿名对象)
    用一个类型去初始化另外一个类型 T t1 = t2
    用花括号列表初始化一个数组中的元素或者一个聚合类(C++primer 266)
    struct data {
    int a;
    string s;
    };
    // data test; test.a = 1; test.s = "abcd";
    data test = {1, "abcd"};

    注意:

    //匿名对象的去和留,关键看,返回时如何接
    //若返回的匿名对象,赋值给另外一个同类型的对象,那么匿名对象会被析构
    //若返回的匿名对象,来初始化另外一个同类型的对象,那么匿名对象会直接转成新的对象

    调用测试

    用一个类型去初始化另外一个类型
    Test4 t2 = t1;  // 用t1来初始化t2  拷贝构造函数
    Test4 t3(t1); // 用一个对象初始化另一个对象
    #include <iostream>
    
    using namespace std;
    // 同一个项目最好不要有相同的类名(防止串包)
    class Test4
    {
    public:
        Test4(int a, int b)  // 调用有参构造函数
        {
            m_a = a;
            m_b = b;
            cout << "有参构造函数" << endl;
        }
        // 赋值构造函数(拷贝构造函数)
        Test4(const Test4 & t)
        {
            cout << "拷贝构造函数" << endl;
            m_a = t.m_a + 100;
            m_b = t.m_b + 100;
        }
        void printT()
        {
            cout << "普通成员函数" << endl;
            cout << "m_a = " << m_a << " m_b = " << m_b << endl;
        }
    private:
        int m_a;
        int m_b;
    };
    // 构造函数是用来初始化的(拷贝..,构造函数)
    
    // 1 拷贝构造函数;用一个对象去初始化另一个对象
    int main()
    {
        Test4 t0(1,2);
        Test4 t1(1,2);
    
    //  *** 赋值=操作  不会调用构造函数 ****
    //  operator=  运算符重载
        t0 = t1;   // 用t1给t0 赋值  和 初始化 是两个概念
    
    // 第一种调用时机
        Test4 t2 = t1;  // 用t1来初始化t2  拷贝构造函数
        t2.printT();
    
    // 第二种调用时机
        Test4 t3(t1); // 用一个对象初始化另一个对象
        t2.printT();
        return 0;
    }
    调用一
    将一个对象作为实参传递给一个非引用类型的形参
    f(类的对象作为参数); // b实参去初始化形参 会调用拷贝构造函数,
    void f(类名 非饮用形参)
    #include <iostream>
    using namespace std;
    
    class Location
    {
    public:
        Location(int _x, int _y)
        {
            x = _x;
            y = _y;
            cout << "	构造函数" << endl;
        }
        // 拷贝构造函数 用一个对象初始化另一个对象
        Location(const Location &obj)
        {
            x = obj.x;
            y = obj.y;
            cout << "	拷贝构造函数" << endl;
        }
        int getX() {return x;}
        int getY() {return y;}
    
    private:
        int x;
        int y;
    
    };
    // 业务函数
    void f(Location p)
    {
        cout << p.getX() << endl;
    }
    void play()
    {
        Location a(1, 2);
        Location b = a;
        cout << "	b对象已经初始化完毕" << endl;
        f(b); // b实参去初始化形参 会调用拷贝构造函数
    }
    int main()
    {
    
        play();
        return 0;
    }
    调用二
    从一个返回类型为非引用的函数返回一个对象(匿名对象)
    #include <iostream>
    using namespace std;
    
    class Location
    {
    public:
        Location() = default;
        Location(int _x, int _y)
        {
            x = _x;
            y = _y;
            cout << "	构造函数" << endl;
        }
        // 拷贝构造函数 用一个对象初始化另一个对象
        Location(const Location &obj)
        {
            x = obj.x;
            y = obj.y;
            cout << "	拷贝构造函数" << endl;
        }
    
        ~Location()
        {
            cout << "	析构函数" << endl;
        }
        int getX() {return x;}
        int getY() {return y;}
    
    private:
        int x;
        int y;
    
    };
    // 结论1: 函数的返回值是一个元素(复杂类型) 返回的是一个新的匿名对象
    // (所以会调用匿名对象类的拷贝构造函数)
    
    // 结论2: 有关匿名对象的去和留
    // 如果用匿名对象 初始化 另外一个同类型的对象,匿名对象转成有名对象(objplay3函数)
    // 如果匿名对象   赋值(=) 给另外一个同类型的对象, 匿名对象马上被析构(objplay4)
    
    // 特别注意这里 在不同的编译器上不同,A应该会在返回时(就算不接收)也会调用拷贝构造函数
    // 匿名对象的去和留
    
    // 你这么写代码,c++编译器的大牛们:
    // 我就给你返回一个新对象(没有名字)
    Location g()  // 最好在objplay4时使用此函数
    {
        Location A(1, 2);
        return A;   // 这里返回时会调用拷贝构造函数
    }
    
    void objplay2()
    {
        g();
    }
    
    void objplay3()
    {
        // 用匿名对象初始化m,c++编译器 直接把匿名对象转成m
        // 从无名,转为有名
    
        Location m = g();   // 这里不会再次调用拷贝构造函数了(匿名对象时已经调用了)
        cout << "	匿名对象,被扶正,不会被析构掉";
        cout << m.getY() << endl;
    }
    
    void objplay4()
    {
        // 用匿名对象赋值给m2后,匿名对象被析构
        Location m2(1, 2);
        m2 = g();
    
    
        cout << "	因为用匿名对象=m2,匿名对象被析构";
        cout << m2.getY() << endl;
    }
    
    
    int main()
    {
    //  objplay2();
    //  objplay3();
    //  objplay4();
    
        return 0;
    }
    匿名对象

    https://www.cnblogs.com/xiaokang01/p/9160475.html#_label1_4

    看函数返回值的匿名对象

    深浅拷贝-->后面有个static

    当在类中出现指针时就要注意了,出现指针(内存重新分配)时不能使用编译器的构造函数和赋值函数了还有析构函数,要自己写

    深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。

    需要写深拷贝时写成了浅拷贝带来的问题:
    两个指针指向同一块内存,当一个释放了,另一个也没有了,但是你并不知道另一个也没有了,就会造成很大的错误
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    
    class Name
    {
    public:
        Name (const char *mp)
        {
            len = strlen(mp);
            p = (char *)malloc(sizeof(len+1)); // 注意细节
            strcpy(p, mp);
    
        }
    
        //Name obj2 = obj1;
        // 解决方案:手工编写拷贝构造函数,使用深拷贝
        Name (const Name &obj1)
        {
            len = obj1.len;
            p  = (char *)malloc(sizeof(len+1));   // 如果不这样写,就会让两个指针指向同一块内存
            strcpy(p, obj1.p);
        }
        ~Name ()
        {
            cout << "析构函数" << endl;
            if (p != NULL)
            {
                free(p);
                p = NULL;
                len = 0;
            }
        }
    private:
        char *p;
        int len;
    
    
    };
    
    // 对象析构的时候会出现,错误
    // 调试存在bug
    // 析构的时候会出现二次释放
    //默认的拷贝构造函数,如果要对指针进行拷贝,则只是浅拷贝,拷贝过后是两个变量指向
    //同一段内存,释放拷贝的obj2后,obj1的指针就是垃圾值,在释放就会出错
    void objmain()
    {
        Name obj1("abcde");
        Name obj2 = obj1;
        Name obj3("obj3");
        //  obj3 = obj1;  // 等号操作 c++编译器会对=进行默认的重载(同样会发生二次释放的问题)
        // 就需要手动的写 operator= 函数
    }
    
    int main()
    {
        objmain();
    }
    例子

    https://www.cnblogs.com/jin521/p/5600488.html

    对象的构造和析构函数的调用顺序

    构造函数:由内到外

    析构函数:由外到内

    #include <iostream>
    using namespace std;
    
    class A
    {
    public:
        A(int _a)
        {
            m_a = _a;
            cout << "a = " << m_a << endl;
            cout << "构造函数" << endl;
        }
        ~A()
        {
            cout << "析构函数" <<"a = " << m_a << endl;
        }
    private:
        int m_a;
    };
    
    // 构造函数初始化列表,解决了:在B类中 组合了一个A 类对象(A类设计了构造函数)
    // 根据调用函数的调用规则,写了A的构造函数必须要用,没有机会初始化A
    // 新的语法规则
    // constrouctor :: constructor() : m1(v1), m2(v2),m3(v3)  {}
    
    class B
    {
    public:
        B(int _a, int _a2) : a1(1), a2(2),c(0)
        {
    
        }
        B(int _b1, int _b2, int m, int n) : a1(m), a2(n),c(0)
        {
            m_b1 = _b1;
            m_b2 = _b2;
            cout << "B的构造函数" << endl;
        }
        ~B()
        {
            cout << "B的析构函数" << endl;
        }
    private:
        int m_b1;
        int m_b2;
        A a1;
        A a2;
        const int c;
    
    };
    
    //2 首先执行 被组合的对象的构造函数
    // 如果组合对象有多个,就按照定义顺序,不按照初始化列表
    
    // 析构函数:和构造函数 相反
    
    // 3被组合对象的构造顺序,与定义顺序有关系,与初始化列表没有关系
    
    // 4初始化列表用来给const属性赋值
    void objplay1()
    {
    //    A a1(10);
    //    B objB(1, 2);
    
        // 参数传递
        B objB2(1, 2, 3, 4);
    }
    
    int main()
    {
        objplay1();
        return 0;
    }
    View Code
    #include <iostream>
    using namespace std;
    // 未完
    class ABCD
    {
    public:
        ABCD(int a, int b, int c)
        {
            this->a = a;
            this->b = b;
            this->c = c;
            cout << "ABCD的构造函数" << endl;
        }
    
        ~ABCD()
        {
            cout << "ABCD的析构函数" << endl;
        }
    
        int getA()
        {
            return this->a;
        }
    
    private:
        int a;
        int b;
        int c;
    
    };
    
    class MyE
    {
    public:
        MyE() : abcd1(1, 2, 3), abcd2(4, 5, 6), m(100)
        {
            cout <<"MyE()构造函数" << endl;
        }
        ~MyE()
        {
            cout <<"~MyE 析构函数" << endl;
        }
        
        //    MyE m2 = my;
        MyE(const MyE & obj) : abcd1(7, 8, 9), abcd2(10,11, 12), m(100)
        {
            cout << "MyE(const MyE & obj)" << endl;
        }
    
        void doThing(MyE myel)
        {
            cout << myel.abcd1.getA() << endl;
        }
    private:
        ABCD abcd1;  // c++编译器不知道啊如何构造abcd1
        ABCD abcd2;
        const int m;
    };
    
    
    int run2()
    {
        MyE my;
    //    MyE m2 = my;
        return 0;
    }
    int main()
    {
        run2();
        return 0;
    }
    一定要看

    new和delete

    1 malloc free c语言中的函数
    new delete c++的操作符

    2 new 基础类型变量, 分配数组类型变量,分配类对象

    malloc 不会调用构造函数,但是new可以
    free 不会调用析构函数,但是delete可以
    其他可以替换

    new int;  //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针)
    new int(100);  //开辟一个存放整数的空间,并指定该整数的初值为100,返回一个指向该存储空间的地址
    new char[10];  //开辟一个存放字符数组(包括10个元素)的空间,返回首元素的地址
    new int[5][4];  //开辟一个存放二维整型数组(大小为5*4)的空间,返回首元素的地址
    float *p=new float (3.14159);  //开辟一个存放单精度数的空间,并指定该实数的初值为//3.14159,将返回的该空间的地址赋给指针变量p
    理论

    用new分配数组空间时不能指定初值。如果由于内存不足等原因而无法正常分配空间,则new会返回一个空指针NULL,用户可以根据该指针的值判断分配空间是否成功。

    new基础类型
    // 分配基础类型
    int main()
    {
    //    int *a = (int *)malloc(sizeof(int));
    
        int *p = new int;  // 分配基础类型
        *p = 20;
        delete p;
    
        int *p2  = new int(30);
        cout << "*p2 = " <<  *p2<< endl;
        delete p2;
        return 0;
    }
    new基础类型

    new数组类型

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    
    // 分配数组类型
    int main()
    {
        int *p = (int *)malloc(sizeof(int) *10);  // int a[10]
        p[0] = 1;
        free(p);
    
        // c++分配数组
        int *arr = new int[10];
        arr[1] = 100;
        cout << arr[1] << endl;
        delete []arr;   // 数组不要把它忘记
    
        char *str = new char[10];
        strcpy(str, "abcd");
        cout << str << endl;
        delete []str;
        return 0;
    }
    数组类型

    new类 类型

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    
    // 分配对象
    class Test
    {
    public:
        Test(int _a)
        {
            a = _a;
            cout << "构造函数执行" << endl;
        }
        ~Test()
        {
            cout << "析构函数执行" << endl;
        }
    private:
        int a;
    };
    
    // new可以调用构造函数,delete 可以调用类的析构函数
    // 和malloc不能       free 不能
    int main()
    {
        Test *t = (Test*)malloc(sizeof(Test));
        free(t);
    
        Test *pT = new Test(10);
        delete pT;
        return 0;
    }
    类 类型

    静态成员变量,静态成员函数static

    静态成员变量

    关键字 static 可以用于说明一个类的成员,
    静态成员提供了一个同类对象的共享机制
    把一个类的成员说明为 static 时,这个类无论有多少个对象被创建,这些对象共享这个 static 成员
    静态成员局部于类,它不是对象成员
    
    
    #include <iostream>
    using namespace std;
    
    class AA
    {
    public:
        void printC()
        {
            cout << "c:" << c <<  endl;
        }
        void AddC()
        {
            c++;
        }
        // 静态函数中,不能使用普通成员变量,普通成员函数
        static void getC() // 静态成员函数
        {
            cout << "c:" << c <<  endl;
            // 请问在静态函数中 可以的调用 普通成员函数么
            // 不能
            //cout << "a:" << a << endl;  // 报错:对非静态成员AA::a的非法引用
        }
    private:
        int a;
        int b;
        static int c;  // 注意这个c是共用的,多个类的值相同,注意他的初始化
    };
    
    int AA::c = 10; // c的初始化
    
    int main()
    {
        AA a1, a2, a3;
    
        a1.printC();  // 10
        a1.AddC();  //11
        a1.printC(); // 11
    
        a2.printC(); // 11
    
        // 静态成员函数的调用方法
        a1.getC(); // 用对象点
        AA::getC();
        return 0;
    }
    测试
    再说说static的用法(三个明显的作用一定要答出来)
    
    1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
    2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
    3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用
    
    4)类内的static成员变量属于整个类所拥有,不能在类内进行定义,只能在类的作用域内进行定义
    
    5)类内的static成员函数属于整个类所拥有,不能包含this指针,只能调用static成员函数
    
    static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
    
    static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
    static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
    static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
    再说说static的用法(三个明显的作用一定要答出来)

    http://www.cnblogs.com/33debug/p/7223869.html

     静态成员函数

    静态成员函数数冠以关键字static
    静态成员函数提供不依赖于类数据结构的共同操作,它没有this指针
    在类外调用静态成员函数用 “类名 :: ”作限定词,或通过对象调用
     
    疑难问题:静态成员函数中,不能使用普通变量。
    //静态成员变量属于整个类的,分不清楚,是那个具体对象的属性。

    强化训练

    某商店经销一种货物。货物购进和卖出时以箱为单位,各箱的重量不一样,
    因此,商店需要记录目前库存的总重量。
    现在用C++模拟商店货物购进和卖出的情况。
    #include "iostream"
    
    using namespace std;
    
    class Goods {
    public :
        Goods(int w) {
            weight = w;
            total_weight += w;
        }
    
        ~ Goods() { total_weight -= weight; }
    
        int Weight() { return weight; };
    
        static int TotalWeight() { return total_weight; }
    
        Goods *next;
    private :
        int weight;
        static int total_weight;
    };
    
    int  Goods::total_weight = 0;
    
    //r尾部指针
    void purchase(Goods *&f, Goods *&r, int w) {
        Goods *p = new Goods(w);
        p->next = NULL;
        if (f == NULL) f = r = p;
        else {
            r->next = p;
            r = r->next;
        } //尾部指针下移或新结点变成尾部结点
    }
    
    void sale(Goods *&f, Goods *&r) {
        if (f == NULL) {
            cout << "No any goods!
    ";
            return;
        }
        Goods *q = f;
        f = f->next;
        delete q;
        cout << "saled.
    ";
    }
    
    int main() {
        Goods *front = NULL, *rear = NULL;
        int w;
        int choice;
        do {
            cout << "Please choice:
    ";
            cout << "Key in 1 is purchase,
    Key in 2 is sale,
    Key in 0 is over.
    ";
            cin >> choice;
            switch (choice)        // 操作选择
            {
                case 1 :                           // 键入1,购进1箱货物
                {
                    cout << "Input weight: ";
                    cin >> w;
                    purchase(front, rear, w);         // 从表尾插入1个结点
                    break;
                }
                case 2 :                    // 键入2,售出1箱货物
                {
                    sale(front, rear);
                    break;
                }       // 从表头删除1个结点
                case 0 :
                    break;                    // 键入0,结束
            }
            cout << "Now total weight is:" << Goods::TotalWeight() << endl;
        } while (choice);
        return 0;
    }
    static强化训练

    面向对象模型初探

    
    

    C++编译器是如何管理类、对象、类和对象之间的关系

    :底层通过指针,看传入的指针,然后进行区分

    C++类对象中的成员变量和成员函数是分开存储的
    成员变量:
    普通成员变量:存储于对象中,与struct变量有相同的内存布局和字节对齐方式
    静态成员变量:存储于全局数据区中
    成员函数:存储于代码段中。
    问题出来了:很多对象共用一块代码?代码是如何区分具体对象的那?
    #include <iostream>
    using namespace std;
    // 注意上一个视频的 字节占用数
    class Test
    {
    public:
        Test(int _a, int _b)// ==>  Test(Test *this, int a, int b)
        {
            this->a = _a;
            this->b = _b;
        }
        void print17()
        {
            cout << "a:" << a << endl;
            cout << "b:" << this->b << endl;
        }
        // 1 const写在什么地方  没有关系
        // 2 const修饰的是谁
        // 2-3const 修饰的是this指针所指向的内存空间,修饰的是this指针
    
    
        // void const OpVar(int a, int b)这两个一样 不过一般是放在后面
        void OpVar(int a, int b) const // ==>void OpVar(const Test *this, int a, int b)
        // 更精确点是void OpVar(const Test* cosnt this, int a, int b)
        {
            a = 100;
    //        this->a = 100;  // 报错
    //        this->b = 100;
            cout << "b:" << this->b << endl;
        }
    //     void OpVar(int a, int b) ==>void OpVar(Test* cosnt this, int a, int b)
    private:
        int a;
        int b;
    };
    int main()
    {
        Test t1(1, 2);
        t1.print17();  // ==> printT(&t1);
        return 0;
    }
    看了这个例子秒懂
    #include <iostream>
    using namespace std;
    class Test18
    {
    public:
        int a;
        int b;
        Test18(int a=0, int b=0)
        {
            this->a = a;
            this->b = b;
        }
    public:
        void print18()
        {
            cout << "a:" << a << "	b:" << b << endl;
        }
    
        // 成员函数法
        //   t3 = t1.TestAdd2(t2);
        Test18 TestAdd2(Test18 &t2)
        {
            // 产生一个匿名对象
            Test18 temp(this->a + t2.a, this->b + t2.b);
            return temp;
        }
    
    
        //t1.TestAdd3(t2);
        // 这里返回的是t1
        Test18& TestAdd3(Test18 &t2)
        {
            this->a += t2.a;
            this->b += t2.b;
    
            return *this;  // this 就是t1的地址,*t1又回到t1的元素
        }
        ~Test18()
        {
            cout << "析构函数自动被调用";
            cout << "a:" << a << "	b:" << b << endl;;
    
        }
    
    private:
    
    };
    
    // 全局函数方法
    Test18 TestAdd(Test18 &t1, Test18 &t2)
    {
        Test18 temp(t1.a+t2.a, t1.b + t2.b);
        return temp;
    }
    
    int main1802()
    {
        Test18 t1(1, 2);
        Test18 t2(3, 4);
    
        // t1 = t1+t2;
        t1.TestAdd3(t2);
        t1.print18();
        return 0;
    }
    
    int main1801()
    {
        Test18 t1(1, 2);
        Test18 t2(3, 4);
        Test18 t3;
    
        // t1 + t2;
    //     全局函数法
        t3 = TestAdd(t1, t2);
        t3.print18();
    
    //     成员函数法
    // 先把测试案例写出来 重点是思路
        {
            // 匿名对象的两种接法
            Test18 t4 = t1.TestAdd2(t2); // 匿名对象转正 转给4
            t4.print18();
    
            Test18 t5;
            t5 = t1.TestAdd2(t2);  // 匿名对象 复制给5 最好用这个
            // t5接收后 前面需要调用析构函数,而t4不用
            t5.print18();
        }
        return 0;
    }
    全局函数和成员函数

    友元函数和友元类

    友元函数:在成员函数的前面添加关键字friend ,破坏了 类的封装性, 但是在重载 << 时要用到

    友元类:了解就行

    #include <iostream>
    using namespace std;
    
    class A
    {
    public:
        friend class B; // B类是A类的好朋友,就是说在B类 可以修改A类的  私有属性,私有函数
        // 1声明的位置 和public和private无关系
        friend void modify(A &p, int _a); // 2 modify函数是类A的朋友
    
        A(int a = 0, int b = 0)
        {
            this->a = a;
            this->b = b;
        }
        void printA()
        {
            cout << "a = " << a << "	b = " <<  b << endl;
        }
    private:
        int a;
        int b;
    };
    
    class B
    {
    public:
        void Set(int b)
        {
            Aobject.b = b;
        }
        void printB()
        {
            cout << "Aobject.b = " << Aobject.b << endl;
        }
    private:
        A Aobject;
    };
    
    // 不加友元函数声明就会报错
    void modify(A &p, int _a)
    {
    //    p.a = 100;
        p.a = _a;
    }
    // 友元类 先了解, 友元函数 要会
    // 为什么要设计友元函数
    int main()
    {
        B b1;
        b1.Set(200);
        b1.printB();
        return 0;
    }
    int main2101()
    {
        A a1(1, 2);
        a1.printA();
    
        modify(a1, 300);
        a1.printA();
        return 0;
    }
    了解即可


  • 相关阅读:
    Java 8简明教程
    ASCII码
    正则 取反匹配
    Eclipse 常用快捷键
    MongoDb基本操作
    Mac下eclipse的快捷键
    oracle的字符集设置与乱码
    Java7、Java8 安装卸载问题
    Oracle | PL/SQL Check约束用法详解
    浅谈数据库中的触发器
  • 原文地址:https://www.cnblogs.com/xiaokang01/p/9163833.html
Copyright © 2011-2022 走看看