C++ 面向对象编程

C++ Object-oriented programming

本文关键字:面向对象编程 C++      更新时间:2023-10-16

我有一个问题,因为我很好奇如何处理这样的问题。我有一个名为"Pracownik"(工人(的基类和 2 个由公共 Pracownik 组成的子类;- 信息学- 克西高维(会计师(写作课很容易。使它们非常快,但我对 main 有小问题,因为我正在帮助朋友编程,但我有一段时间没有使用C++了。所以:

这是我的头文件"funkcje.h">

#include <iostream>
using namespace std;

class Pracownik
{
 private:
  string nazwisko;
  int pensja;
 public:
  Pracownik(string="",int=0);
  ~Pracownik();
  string getNazwisko();
  int getPensja();
  friend double srednia_pensja(int,Pracownik);
};
class Informatyk : public Pracownik
{
 private:
  string certyfikat_Cisco;
  string certyfikat_Microsoft;
 public:
  Informatyk(string="",int=0, string="", string="");
  ~Informatyk();
  void info();
};
class Ksiegowy : public Pracownik
{
 private:
  bool audytor;
 public:
  Ksiegowy(string="",int=0, bool=false);
 ~Ksiegowy();
 void info();
};
double srednia_pensja(int,Pracownik);

这些是我的函数"funkcje.cpp"的定义

#include "funkcje.h"
Pracownik::Pracownik(string a,int b)
{
  nazwisko=a;
  pensja=b;
}
Pracownik::~Pracownik()
{
}
string Pracownik::getNazwisko()
{
  return nazwisko;
}
int Pracownik::getPensja()
{
  return pensja;
}

Informatyk::Informatyk(string a, int b, string c, string d) : Pracownik(a,b)
{
  certyfikat_Cisco=c;
  certyfikat_Microsoft=d;
}
Informatyk::~Informatyk()
{
}

Ksiegowy::Ksiegowy(string a, int b, bool c) : Pracownik(a,b)
{
  audytor=c;
}
Ksiegowy::~Ksiegowy()
{
}
void Informatyk::info()
{
  cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
  cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
  cout<<"Certyfikat Cisco: "<<certyfikat_Cisco<<endl;
  cout<<"Certyfikat Microsoft: "<<certyfikat_Microsoft<<endl;
}

void Ksiegowy::info()
{
  cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
  cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
  cout<<"Audytor: ";
  if(audytor)
    cout<<"Tak"<<endl;
  else
    cout<<"Nie"<<endl;
}

double srednia_pensja(int a,Pracownik *b)
{
  return 0;
}

最后是主要的!

#include <iostream>
#include "funkcje.h"
using namespace std;
int main()
{
  Pracownik lista[10];
  Pracownik *lista_wsk = new Pracownik[10];
  Informatyk a("Kowalski1",1000,"Cisco1","Microsoft1");
  Informatyk b("Kowalski2",2000,"Cisco2","Microsoft2");
  Informatyk c("Kowalski3",3000,"Cisco3","Microsoft3");
  Ksiegowy d("Kowalski4",4000,1);
  Ksiegowy e("Kowalski5",5000,0);
  lista[0]=a;
  lista[1]=b;
  lista[2]=c;
  lista[3]=d;
  lista[4]=e;
  Informatyk *ab = new Informatyk("Kowalski1",1000,"Cisco1","Microsoft1");
  Informatyk *ac = new Informatyk("Kowalski2",2000,"Cisco2","Microsoft2");
  Informatyk *ad = new Informatyk("Kowalski3",3000,"Cisco3","Microsoft3");
  Ksiegowy *ae = new Ksiegowy("Kowalski4",3000,1);
  Ksiegowy *af = new Ksiegowy("Kowalski5",3000,0);
  lista_wsk[0]=*ab;
  lista_wsk[1]=*ac;
  lista_wsk[2]=*ad;
  lista_wsk[3]=*ae;
  lista_wsk[4]=*af;
  for(int i;i<5;i++)
    {
      lista[i].info();
      cout<<endl;
    }
  cout<<endl;
  //  for(int i;i<5;i++)
  // {
      //        lista_wsk[i].info();
  //  }

  return 0;
}

好的,这是我的问题:我必须创建填充有基类对象"Pracownik"的数组。次要的我必须创建数组,其中充满了指向类"Pracownik"对象的指针。(希望这两个第一步正确完成(接下来,我必须写入数组 3 个类 Informatic 对象和 2 个类会计师对象。所以我手动创建了 5 个对象,并以这样的方式将它们添加到数组中 array[0]=a;我想这还是不错的。接下来,我必须使用 new 创建类似的对象并将其添加到指针数组中。所以我用 new 创建了数组,并使用 new 创建了指向对象的指针。(希望这是正确的 2(。最后:我不得不在添加到数组对象时使用 info((。这是我的主要问题,如果我的数组是"Pracownik"类型,并且我想使用子类中的函数 info((,我应该怎么做?以及编译器如何知道他是否应该使用来自会计师或Informatic的info((,而我试图使用"for"显示这些信息。

Pracownik数组中,元素的类型为 Pracownik 。当您将元素复制到数组中时,有关属于 Pracownik 子类的对象的任何信息都将丢失。

这称为对象切片,并导致无法在这些对象上调用Informatyk::info()

如果要调用子类的方法,则必须通过在数组中存储指针或引用来防止对象切片。

正如奥斯瓦尔德在他的回答中所说,

Pracownik * lista_wsk = new Pracownik[10];

分配一个包含 10 个Pracownik对象的数组。 这可能不是您想要的。 由于涉及多态性,我们通常想要处理指针或引用。 因此,您需要一个Pracownik *指针数组。 由于您在编译时已经知道它将有 10 个成员,因此此处不需要动态分配。 我想你的意思是写

Pracownik * lista_wsk[10];

相反。 现在我们不把对象,而是把指向对象的指针放到数组中。 例如:

lista_wsk[2] = new Informatyk("Kowalski3", 3000, "Cisco3", "Microsoft3");

然后我们可以像这样迭代项目:

for (unsigned i = 0; i < 10; ++i)
  std::cout << lista_wsk[i]->getNazwisko() << std::endl;

正如您已经发现的那样,不可能在超类对象上调用子类函数成员。 可以通过强制转换在运行时找出实际类型。

for (unsigned i = 0; i < 10; ++i)
  if (Informatyk * info_ptr = dynamic_cast<Informatyk *>(lista_wsk[i]))
    info_ptr->info();

如果可能的话,dynamic_cast返回指向目标类的指针,否则返回一个nullptr(计算结果为 false,因此是条件的(。 但请注意,这被认为是非常糟糕的风格。 最好使用虚拟函数。 因此,添加

virtual void
info()
{
  // Do what is appropriate to do for a plain Pracownik.
  // Maybe leave this function empty.
}

超类,再到子类

virtual void
info()  // override
{
  // Do what is appropriate to do for an Informatyk.
}

子类中具有相同签名的函数被称为覆盖从超类继承的函数。 由于该函数被标记为virtual,编译器将生成额外的代码,以便在运行时确定要调用的函数版本。

如果要编写 C++11,则可以通过将关键字 override 放在其类型之后来显式覆盖,如上所示(取消注释override (。 我建议您使用它来避免因意外拼写错误或其他拼写错误而引起的错误。