C++静态成员和友元成员的理解

简介: 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;
}

运行结果如图:

20200401134307494.png

因为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;
}

完结撒花~

目录
相关文章
|
29天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
82 5
|
2月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
38 3
|
2月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
29 1
|
2月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
46 1
|
2月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
40 3
|
2月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
52 3
|
2月前
|
C++
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
29 0
|
23天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
36 2
|
1月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
79 4
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
86 4