zoukankan      html  css  js  c++  java
  • C++静态成员和友元成员的理解

    面向对象程序设计课堂笔记

    对静态成员的理解

    在之前的学习过程中我们已经了解到模块数据的共享与保护机制,比如:数据成员对外不公开,对象里定义的变量也具有作用域等等。

    对于一个类,函数成员是所有的对象相同的,而数据成员则是各自不同的。如果这时候我们引入了一个新的数据成员,对于所有的对象来说,他的值都是相同的,此时再去对每一个对象定义一次此数据成员则显得冗杂。由此,我们引入了静态数据成员。

    根据上一段的解释,可以看出静态数据成员的简单定义:是类共有的数据,类的所有成员都维护这一个数据。

    在代码中这样定义:

    class A{
    	private:
    		int b;///一般数据成员
    		static int exnum;///静态数据成员
    }
    

    对于程序中的模块,都会在内存中占据一定的存储空间,那么静态数据成员exnum又是如何存储的呢?

    因为静态数据成员是类共有的成员,所以他不会占用对象的存储空间。可以结合下面的代码进行理解:

    #include<bits/stdc++.h>
    using namespace std;
    class A{
        private:
            int b;
            static int exnum;
    };
    int main(){
        A a;
        cout<<sizeof(A)<<endl;
        cout<<sizeof(a)<<endl;
        return 0;
    }
    
    

    运行结果如图:

    在这里插入图片描述

    因为int类型的b在内存中占四个字节,也就说明了exnum并没有存储在对象a中。

    具体有关的理解的博客:传送门

    变量在使用前都需要初始化,这个也不例外。初始化的语法如下:

    int A::exnum=0;
    

    其中“::”是预作用符,表示后面的操作对象属于哪个类。

    定义一个东西后,我们需要使用,那么我们如何访问这一成员呢。

    通过之前的学习,我们可以知道下面的方式是可以访问exnum的:

    #include<bits/stdc++.h>
    using namespace std;
    class A{
        private:
            int b;
            static int exnum;
        public:
            A(){exnum=exnum+1;}///构造函数
            void shownum(){cout<<"当前的生存对象个数为:"<<exnum<<endl;}
            ~A(){exnum=exnum-1;}///析构函数
    };
    int A::exnum=0;
    int main(){
        A a;
        a.shownum();
        return 0;
    }
    

    以上方式是通过对象来访问静态成员,这也就说明了对象具有静态成员的访问权。

    但是如果我们还没有构造对象,又该如何访问呢。

    前面静态数据成员的定义已经指明,静态成员属于类,所以我们可以通过通过类名直接访问。理论上如果exnum是public的,这是可行的,但是exnum是私有的数据成员,由于模块的安全性,语法并不支持这种操作。

    这时候我们希望某些函数的调用也不依赖于对象,就可以再引进一个静态函数了,与静态数据成员类似,这一函数也是属于类,由类直接调用。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    class A{
        private:
            int b;
            static int exnum;
        public:
            A(){exnum=exnum+1;}///构造函数
            static void shownum(){cout<<"当前的生存对象个数为:"<<exnum<<endl;}
            ~A(){exnum=exnum-1;}///析构函数
    };
    int A::exnum=0;
    int main(){
        A::shownum();
        return 0;
    }
    

    关于对友元函数的理解都在代码里了~

    作业:

    #include<bits/stdc++.h>
    using namespace std;
    class StaticTest{
    public:
        StaticTest(int x, int y, int z);  ///内联构造函数在类里的定义
    	void ObjectShowInfo(){
    		cout<<"("<<a<<","<<b<<","<<c<<")"<<endl;
    	}
        static void ObjectShowSum(){///静态函数,调用不依赖于对象
        	cout<<"sum="<<sum<<endl;
    	}
        void ShowObjectInfo(StaticTest& s);///内联函数,输出sum值
    
    private:
        int a, b, c;///一般成员,只能通过对象调用
        static int sum; ///静态数据成员,可以通过对象访问,也可以通过类名直接访问
        //sum记录产生的所有对象的数据成员A、B、C之和
    };
    ///内联构造函数
    StaticTest::StaticTest(int x, int y, int z):a(x),b(y),c(z){
        cout<<"构造函数"<<endl;
        sum+=x+y+z;///更新sum的值
    }
    int StaticTest::sum=0;///静态数据成员的初始化,一定不要忘记
    void StaticTest::ShowObjectInfo(StaticTest& s)
    {   //一种是直接操作数据成员输出
       //调用其他函数功能
       //以上两种方式选一
       ///调用函数功能进行成员的输出
        cout<<"调用函数功能进行成员的输出"<<endl;
        s.ObjectShowInfo();
        s.ObjectShowSum();
        cout<<"直接操作进行数据成员的输出"<<endl;
        cout<<s.a<<" "<<s.b<<" "<<s.c<<" "<<s.sum<<endl;
    }
    int main(void)
    {
    	///生成两个对象  M N
        StaticTest m(1,2,3);
        StaticTest n(4,5,6);
    
    	///调用一般成员显示信息
        m.ObjectShowInfo();
        n.ObjectShowInfo();
    
        ///对象调用静态成员显示信息和sum
        m.ShowObjectInfo(m);
        m.ObjectShowSum();
    
        ///类作用域调用静态成员
        StaticTest::ObjectShowSum();
    
        return 0;
    }
    
    /*
    运行结果如下:
    构造函数
    构造函数
    (1,2,3)
    (4,5,6)
    调用函数功能进行成员的输出
    (1,2,3)
    sum=21
    直接操作进行数据成员的输出
    1 2 3 21
    sum=21
    sum=21
    */
    
    
    
    /* 添加友元,float MyDistance( pb,  pe)
     sqrt((pe.x - pb.x) * (pe.x - pb.x) + (pe.y - pb.y) * (pe.y - pb.y));
    */
    
    #include <math.h>
    #include <iostream>
    using namespace std;
    class MyPoint{
    public:
        MyPoint(int ix, int iy):x(ix),y(iy){
            cout<<"构造函数"<<endl;
        }
    
        void print() {
            cout << "(" << x<< "," << y<< ")" << endl;
        }
    
        ///友元之普通函数
        friend double MyDistance( MyPoint& pb,MyPoint&  pe);
    /*
    要注意:如果友元函数时全局函数,直接声明即可
    但如果该友元函数是某个类中的函数,需要加预作用符说明该函数属于哪一类
    */
    private:
        int x;
        int y;
    };
    /*
    友元函数的定义:如果一个类允许某外部函数具有其成员函数的权限
    即可以直接访问类内成员,那么在该类的定义中应当声明此函数为友元函数
    */
    double MyDistance( MyPoint& pb,MyPoint&  pe){
        return sqrt(1.0*(pe.x - pb.x) * (pe.x - pb.x) + 1.0*(pe.y - pb.y) * (pe.y - pb.y));
    }
    int main()
    {
        MyPoint pt1(1, 2);
        MyPoint pt2(1, 4);
        cout << "pt1和pt2之间的距离: " << MyDistance(pt1, pt2) << endl;
        return 0;
    }
    
    
    
    #include <math.h>
    #include <iostream>
    using namespace std;
    /*
    如果想要一个类里的函数都变为另一个类里的友元函数,
    可以直接逐个把其变为友元函数,但这样显得过于繁杂,
    所以我们也可以将该类变为友元类,语法是先在类前加前向声明,
    再在类内定义说明
    */
    
    ///类的前向声明
    class MyLine;
    
    class MyPoint
    {
    public:
        MyPoint(int ix = 0, int iy = 0) :x(ix), y(iy) {cout<<"构造函数"<<endl;}
    
        void print() {
            cout << "(" << x<< "," << y<< ")" << endl;
        }
    
        ///友元类
        friend class MyLine;
    
    private:
        int x;
        int y;
    };
    
    
    class MyLine
    {
    public:
        double MyDistance(MyPoint& pb,MyPoint&  pe){
            return sqrt(1.0*(pe.x - pb.x) * (pe.x - pb.x) + 1.0*(pe.y - pb.y) * (pe.y - pb.y));
        }
    
        void ShowPoint(MyPoint& p){
    	   cout << "(" <<p.x<< "," <<p.y<< ")" << endl;
    	}
    
        void showLine(MyPoint& pb,MyPoint&  pe) {
    	    ShowPoint(pb);
    	    ShowPoint(pe);
    	}
    };
    
    int main(void)
    {
        MyPoint pt1(1, 2);
        MyPoint pt2(3, 4);
    
        MyLine line;
        line.showLine(pt1,pt2);
        cout << "pt1和pt2之间的距离: " << line.MyDistance(pt1, pt2) << endl;
        return 0;
    }
    
    

    完结撒花~

  • 相关阅读:
    buuctf-misc 一叶障目
    攻防世界-web ics-05
    攻防世界-web ics-06
    攻防世界-web NewsCenter
    攻防世界-web upload1
    攻防世界-web unserialize3
    攻防世界-web PHP2
    攻防世界-web2
    gitlab常用命令
    javascript编程风格
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853159.html
Copyright © 2011-2022 走看看