C ++:抽象类

加斯顿

我仍在学习抽象类的工作方式,我想知道我是否处在正确的轨道上。

这是我的简化程序:

class CPerson
{
public:
  CPerson() = default;
  virtual int getMat() = 0;
};

class CStudent : public CPerson
{
public:
  CStudent() = default;
  CStudent(int MatriculationNr) { this->MatriculationNr = MatriculationNr;}

  int getMat() { return MatriculationNr;}

private:
  int MatriculationNr;
};

class CTeacher : public CPerson
{
  public:
  CTeacher() = default;
  int getMat(){ return 0;} 

private:
  std::string name;
};

int main()
{
  std::vector<CPerson*> test;

  test.push_back(new CStudent(9898));
  CTeacher *a = new CTeacher();


  return 0;
}

在课堂上CTeacher,我没有与CStudentMatriculationNr相同的私有变量,所以我返回0。程序正常运行。但是我在这里做的正确与否吗?

另一个与抽象类有关的问题:假设我们使用virtual int& getMat() = 0;(带有引用),我们应该在CTeacher类中返回什么0在这种情况下不起作用,对吗?

我们应该将变量初始化为0,以便可以在此函数中将其返回,还是有更好的实现?

拜伦

下面的代码示例应以相当现代的C ++方式回答您的问题。

    #include <iostream>
    #include <string>
    #include <vector> 
    #include <memory>
    


    // I have added a `std::string name` to the CPerson class and 
    // a `std::string subject` to the CTeachers class 
    // so both derived classes, CStudent and CTeacher have a name 
    // of the person involved and each derived class has
    // something only it needs, MatrikulationNr for CStudent and 
    // Subject of teaching for CTeacher in order to deliver a more 
    // complete and more clearifying answer.



    class CPerson {

        int dummyMatriculationNr{ 0 };
        std::string dummySubject{ "noTeacher" };

        protected:

        std::string name;

        public:

        std::string getName() { return name; }
        virtual int& getMat() { return dummyMatriculationNr; }
        virtual std::string getSubject() { return dummySubject; }

    };
        


    class CStudent : public CPerson {

        int MatriculationNr{ 0 };

        public:   

        CStudent() = delete; // we dont want anyone using this constructor

        explicit CStudent(std::string name, int MatriculationNr) :  
                                MatriculationNr{ MatriculationNr } {
            this->name = name;
        }    

        int& getMat() { return MatriculationNr; }

    };
      

  
    class CTeacher : public CPerson {

        std::string subject{ "" }; // Subject of teaching  

        public:

        CTeacher() = delete; 

        explicit CTeacher(std::string name, std::string subject) : 
                                                subject{ subject } { 
            this->name = name;
        }

        std::string getSubject() { return subject; }

    };
    
    

    int main() {
    
        std::vector<std::unique_ptr<CPerson>> vp;
        
        vp.push_back(std::make_unique<CStudent>("aStudentsName", 8989 ));// or emplace_back
        vp.push_back(std::make_unique<CTeacher>("aTeachersName", "mathematics")); 
    
        for (auto& e : vp) 
        std::cout << "Name: " << e->getName() << " MatrNo: " << e->getMat() 
                  << " TeachingSubject: " << e->getSubject() << std::endl;
    
    }

希望以上示例回答您的问题。但是,使用关键字virtual会在运行时创建一个虚拟函数表(通常称为vtable),这会降低性能,并且不再被视为高性能计算。

getMat()当仅在一个CStudents派生类中需要一个函数时,它在所有派生类中都具有可用功能也是令人困惑的尽管在任何其他类中没有意义,但此函数仍在此处返回一些伪值。那可能很烦人。getSubject()CTeacher中功能相同查看输出:

Name: aStudentsName MatrNo: 8989 TeachingSubject: noTeacher
Name: aTeachersName MatrNo:    0 TeachingSubject: mathematics

考虑到解决你的问题,没有任何关键字virtual,并具有getMat()int MatriculationNrCStudents所有的,而不是在基类。我知道使用虚拟技术很诱人,但是应该尽量避免使用它。例如,MFC,Microsoft Foundation Classes(也许是有史以来最大的类继承项目)根本没有使用虚拟!考虑以下代码作为示例:

#include <iostream>
#include <string>
#include <vector>
#include <variant>

// a code version without virtual

class CPerson {

protected:

    std::string name;

    public:

    std::string getName() { return name; }

};



class CStudent : public CPerson {

    int MatriculationNr{ 0 };

    public:

    CStudent() = delete; // we dont want anyone using this constructor

    explicit CStudent(std::string name, int MatriculationNr) : MatriculationNr{ MatriculationNr } {
        this->name = name;
    }

    int& getMat() { return MatriculationNr; }

};



class CTeacher : public CPerson {

    std::string subject{ "" }; // Subject of teaching

    public:

    CTeacher() = delete;

    explicit CTeacher(std::string name, std::string subject) : subject{ subject } {
        this->name = name;
    }

    std::string getSubject() { return subject; }

};



int main() {

    std::vector<CStudent> vs; // auto-deleted through RAII
    std::vector<CTeacher> vt; // and good for serialisation and or database communication

    vs.push_back(CStudent{ "aStudentsName", 9898 });
    vt.push_back(CTeacher{ "aTeachersName", "mathematics" });
    
    for (auto s : vs)
        std::cout << s.getName() << " " << s.getMat() << std::endl;

    for (auto t : vt)
        std::cout << t.getName() << " " << t.getSubject() << std::endl << std::endl;

    // and here we are done already,
    // not listing the two different types in one vector
    // but just using a vector for each derived class
    //
    // but lets try put them now into one vector
    // using a more modern way through std::variant
    // which keps all data in the vector and not only the 
    // CPerson part.


    std::vector<std::variant<CStudent, CTeacher>> people;

    // we could, for example, copy from above vectors
    for (auto e : vs) 
        people.push_back(e);

    for (auto e : vt)
        people.push_back(e);

    // we could insert new ones
    people.push_back(CStudent { "aStudentsName1", 9899 });
    people.push_back(CTeacher { "aTeachersName1", "physics" });

    // and take that vector apart again
    std::cout << std::endl << "Output from vector of variant:" << std::endl;
    for (auto& e : people)
        if (std::holds_alternative<CStudent>(e)) {
            CStudent& s = std::get<CStudent>(e);
            std::cout << s.getName() << " " << s.getMat() << std::endl;
        }
        else if (std::holds_alternative<CTeacher>(e)) {
            CTeacher& s = std::get<CTeacher>(e);
            std::cout << s.getName() << " " << s.getSubject() << std::endl;
        }

}

有很多方法可以实现避免虚拟的目标,希望您确实喜欢上面的方法。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章