c++面向对象程序设计教程——类(二)

简介: c++面向对象程序设计教程——类(二)

类的静态成员


上面我们创建了对象后,对其进行了空间申请,但是,每次用完后,都会释放,那如果我们要共享某一个对象的数据成员的时候,我们又应该怎么做喃?那就要用到我们下面要学到的知识,静态成员;


1.静态数据成员


//静态数据成员不属于任何对象,它不因对象的建立而产生,也不因对象的析构而删除,它是类定义的一部分,所以使用静态

//数据成员不会破坏类的隐蔽性,类中的静态数据成员不同于一般的静态变量,也不同于其他数类数据成员,它在程序开始运行时创建而不是在对象创建时创建。

//他所占空间的回收也不是在析构函数时进行而是在程序结束时进行;


2.静态数据成成员初始化


必须对静态数据成员初始化,因为这样程序在编译的时候才会为静态数据成员分配一个具体的数据存储空间。

静态数据成员的初始化u一般的数据成员不同,他的初始化不能在构造函数中完成,静态数据成员格式化为:

<数据类型><类名>::<静态数据成员>=<初始值>;

这里的作用域运算符“::”用来说明数据成员所属类;


静态数据成员的引用


静态数据成员可以说明为共有的,私有的或保护的,若为公有的可直接访问,引用静态数据成员的格式:

<类名>::<静态数据成员>;;

由于静态数据成员是类的成员,用对象名也可以。但通常用上述方法引用,因为静态数据成员不从属于任何一个具体对象;


//静态数据成员不属于任何对象,它不因对象的建立而产生,也不因对象的析构而删除,它是类定义的一部分,所以使用静态
    //数据成员不会破坏类的隐蔽性,类中的静态数据成员不同于一般的静态变量,也不同于其他数类数据成员,它在程序开始运行时创建而不是在对象创建时创建。
    //他所占空间的回收也不是在析构函数时进行而是在程序结束时进行;
#include<iostream>
using namespace std;
//定义点类;
class Point
{
public:
    static int countP;//静态数据成员必须初始化,他不能在构造函数中初始化,静态数据成员的初始化格式为:
    //<数据类型><类名>::<静态数据成员>=<初始值>;
    Point(int = 0, int = 0);
    ~Point();//析构函数;
private:
    int X, Y;
};
Point::Point(int x, int y)
{
    X = x;
    Y = y;
    cout << " Constructor is called!" << endl;
    countP++;//每创建一个对象,数值加一; 
}
Point::~Point()
{
    cout << "Destructor is called!" << endl;
    countP--;//每析构一个对象,点数-1;
    cout << "现在对象数是:" << countP << endl;
}
//静态数据成员初始化和定义;
int Point::countP = 0;
//主函数;
//静态数据成员的引用的格式为:
//<类名>::<静态数据成员>;
int main(void)
{
    Point p(4, 5);//第一个对象;
    cout << "现在对象数是:" << Point::countP << endl;
    Point B(7, 8);//第二个对象;
    cout << "现在对象数是:" << B.countP << endl;
}



静态成员函数


静态成员函数的定义和其他成员函数一样,静态成员函数与静态数据成员类似,从属于类,在一般函数前面加上static关键字;

调用静态成员函数的格式为:

<类名>::<静态成员函数>(参数);

或者

<对象名>.<静态成员函数>(参数);


#include<iostream>
using namespace std;
//定义点类;
class Point
{
public:
    Point(int = 0, int = 0);
    ~Point();
    static void dispcount();
private:
    int X, Y;
    static int countP;
};
Point::Point(int x, int y)
{
    X = x;
    Y = y;
    cout << "Constructor is called!" << endl;
    countP++;
}
Point::~Point()
{
    cout << "Destructor is called!" << endl;
    countP--;
    cout << "现在的对象数是:" << Point::countP << endl;
}
void Point::dispcount()
{
    cout << "现在的对象数:" << Point::countP<<endl; 
}
int Point::countP = 0;//静态数据成员初始化;
int main(void)
{
    Point A(4, 5);
    Point::dispcount();
    Point B(7, 8);
    Point::dispcount();
    return 0;
}
通过上述代码我们可以发现对于静态成员函数的引用就只有两种方式,由于没有this指针,故就通过对象来访问。



类的友元


上面的程序我们不难发现,我们在构造函数和成员的时候,都是在公有成员和私有成员中操作的,那么保护成员和私有成员的数据又该如何访问?

那就要用到接下来学到的友元函类;


友元函数

在类里声明一个普通函数,加上关键字friend,就成了该类的友元函数,他可以访问类中一切成员。

friend<函数类型><友元函数名>(参数列表);

例如:用友元函数求两点的距离


#include<iostream>
#include<cmath>
using namespace std;
class Point
{
public:
    Point(double xi, double yi) { X = xi, Y = yi; };
    void destroy();
    friend double length(Point& a, Point& b);
private:
    int X, Y;
};
double length(Point& a, Point& b)//不需要将友元函数设计为成员函数;
{
    double dx = a.X - b.X;
    double dy = a.Y - b.Y;
    return sqrt(dx * dx + dy * dy);
}
int main(void)
{
    Point p1(3, 5), p2(4, 6);
    double d = length(p1, p2);
    cout << "The distence is" << d << endl;
}



上面的代码我们可以发现,在对友元函数进行初始化的时候,是不需要表明类的。也就是说,一个普通的函数可以定义成类的友元函数,一个类的成员函数也可以定义成另一个类的友元函数,友元成员函数的使用与一般友元函数的使用基本相同,只是通过相应的类或者对象名来引用。


友元类


除了函数外,一个类也可以被声明为另一个类的友元,该类被称作友元类。

假设有类A,和类B,若在类B的定义中将类A声明为友元,那么,类A被称为类B的友元类,它所有的成员函数都可以访问类B中的任意成员。友元类的声明格式:

friend class<类名>;

例如:将整个教师类teacher看成是学生类student的友元类,教师可以给学生设置学号,输入学生成绩;


#include<iostream>
using namespace std;
class student
{
public:
  friend class teacher;
  student() {};//构造函数;
private:
  int number, score;
};
class teacher
{
public:
  teacher(int i, int j);
  void displayxy();
private:
  student a;
};
teacher::teacher(int i, int j)
{
  a.number = i;
  a.score = j;
}
void teacher::displayxy()
{
  cout << "No=" << a.number<<endl;
  cout << "score=" << a.score << endl;
}
int main(void)
{
  teacher t1(1001, 89), t2(1002, 78);
  cout << "第一个学生的信息:";
  t1.displayxy();
  cout << "第二个学生的信息:";
  t2.displayxy();
}


友元的作用主要是为了提高小路和方便编程,但友元破坏了类的整体性,使用时要权衡利弊;



学习了这么多,我们来来来练习一下吧!

学生成绩管理系统:


#include<iostream>
#include<string>
using namespace std;
class Student
{
  int num;//学号;
  string name;//姓名
  float score;//成绩
  Student* per;//当前节点;
  Student* next;//下一个结点指针
public:
  Student();//构造函数;
  Student* find(int i_num);//查找指定学好的学生;
  void edit(string i_newname, float i_score);//修改学生信息;
  void erase();//删除指定学号的学生;
  int add(Student* i_newStudent);//增加学生;
  int getno();//获得学生学号;
  string getname();//获得学生姓名;
  float getscore();//获得学生成绩;
  static int maxno;//当前最大学号;
};
//构造函数;
Student::Student()
{
  score = 0.0;
  per = NULL;
  next = NULL;
}
//查找指定学好的学生函数;
Student* Student::find(int i_num)
{
  if (i_num == num)
  return this;
  if (next != NULL)
  {
  return next->find(i_num);//递归;
  }
  return NULL;
}
//修改学生的名字的函数;
void Student::edit(string i_name, float i_score)
{
  if (i_name == "")
  return;
  name = i_name;
  score = i_score;
}
//删除指定学号的学生函数;
void Student::erase()
{
  if (num < 0)
  return;
  if (per != NULL)
  per->next = next;
  if (next != NULL)
  next->per = per;
  next = NULL;
  per = NULL;
}
//增加学生函数;
int Student::add(Student* i_newStudent)
{
  int num = maxno + 1;
  while (true)
  {
  if (NULL == find(num))
    break;
  num += 1;
  }
  Student* tmp = this;
  while (true)
  {
  if (tmp->next == NULL)
    break;
  tmp = tmp->next;
  }
  tmp->next = i_newStudent;
  i_newStudent->next = NULL;
  i_newStudent->per = tmp;
  i_newStudent->num = num;
  return num;
}
//可以得到以下的相关信息函数;
int Student::getno() { return num; }
string Student::getname() { return name; }
float Student::getscore() { return score; }
//静态成员的初始化及程序的主函数;
int Student::maxno = 1000;
int main()
{
  Student* studentroot = new Student();
  string input1;
  float input2;
  Student* tmp = NULL;
  while (true)
  {
  cout << "输入指令:查找(F),增加(A),编辑(E),删除(D),退出(Q)" << endl;
  cin >> input1;
  if (("F" == input1) || ("f" == input1))
  {
    cout << "输入学号:";
    int id = -1;
    cin >> id;
    tmp = studentroot->find(id);
    if (tmp == NULL)
    {
    cout << "没找到" << endl;
    continue;
    }
    cout << "学号:" << tmp->getno();
    cout << "姓名:";
    string name;
    if ((name = tmp->getname()) != "")
    {
    cout << name << endl;
    }
    else
    {
    cout << "未输入" << endl;
    cout << "成绩:" << tmp->getscore() << endl;
    }
  }
  else if ((input1 == "A") || (input1 == "a"))
  {
    cout << "输入姓名,成绩:";
    cin >> input1 >> input2;
    tmp = new Student();
    tmp->edit(input1, input2);
    cout << "学号:" << studentroot->add(tmp) << endl;
  }
  else if (input1 == "E" || input1 == "e")
  {
    cout << "输入学号:";
    int id = 0;
    cin >> id;
    tmp = studentroot->find(id);
    if (tmp == NULL)
    {
    cout << "空号" << endl;
    continue;
    }
    cout << "新姓名,新成绩:";
    cin >> input1 >> input2;
    tmp->edit(input1, input2);
    cout << "更改成功" << endl;
  }
  else if ((input1 == "D") || (input1 == "d"))
  {
    cout << "输入学号:";
    int id = 0;
    cin >> id;
    tmp = studentroot->find(id);
    tmp->erase();
    cout << "已成功删除" << endl;
    delete tmp;
  }
  else if ((input1 == "Q") || (input1 == "q"))
  {
    break;
  }
  else
  {
    cout << "输入有误!" << endl;
  }
  }
  delete studentroot;
  return 0;
}


感兴趣的同学可以自己尝试去运行一下,也可以在现有的程序上进行增添.

相关文章
|
6天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
29 4
|
7天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
26 4
|
30天前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
27 4
|
30天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
21 1
|
30天前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
23 4
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
1月前
|
编译器 C++
【C++类和对象(中)】—— 我与C++的不解之缘(四)
【C++类和对象(中)】—— 我与C++的不解之缘(四)
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
23 3
|
1月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
53 1
|
1月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
19 1