在c++中正确地扩展类

Properly extending a class in C++

本文关键字:扩展 正确地 c++      更新时间:2023-10-16

代码:

class Plant
{
public:
    virtual std::string getPlantName();
    virtual void setPlantName(std::string s);
    virtual std::string getPlantType();
    virtual void setPlantType(std::string s);

};
class Carrot : public Plant
{
public:
    Carrot();
    ~Carrot();
private:
    std::string _plantName;
};

然后:

#include "Carrot.hpp"
Carrot::Carrot() 
{ 

}
Carrot::~Carrot() { }
std::string Carrot::getPlantName() { return _plantName; }

我得到一个链接错误:

Carrot.cpp:16:21: Out-of-line definition of 'getPlantName' does not match any declaration in 'Carrot'

这里的目标是创建一个Plant类而其他类扩展为class Carrot : public Plant

但是,我不确定的是,我可以只是inlinePlant的功能,这样我就不必在每个类中创建这些getset函数,如胡萝卜或豌豆等?

如果我做了:

inline virtual std::string getPlantName( return _plantName; );

可以吗?然后,我会将std::string _PlantName;添加到class Plant,然后当我从Plant创建Carrot时,我得到所有相同的函数,Carrot将具有_plantName等变量,正确吗?

也就是

class Plant
{
public:
    inline virtual std::string getPlantName( return _plantName; );
    virtual void setPlantName(std::string s);
    virtual std::string getPlantType();
    virtual void setPlantType(std::string s);
private:
    std::string _plantName;
};
class Carrot : public Plant
{
public:
    Carrot();
    ~Carrot();
};
#include "Carrot.hpp"
Carrot::Carrot() 
{ 
    setPlantName(CARROT::plantName);
}
Carrot::~Carrot() { }

如果Plant类的所有对象都应该有类型和名称,都是std::string,那么您可能需要在基类中使用这些公共成员:

// Plant.hpp
class Plant
{
public:
    Plant(); 
    virtual ~Plant(); // virtual destructor!
    virtual std::string getPlantName();
    virtual void setPlantName(std::string s);
    virtual std::string getPlantType();
    virtual void setPlantType(std::string s);
protected:
    std::string _plantName;
    std::string _plantType;
};
// Plant.cpp
#include <Plant.hpp>
std::string Plant::getPlantName() { return _plantName; }
void Plant::setPlantName(std::string s) { _plantName = s; }
... same for type

当使用class Carrot : public Plant创建派生类时,该类将具有相同的数据成员和相同的函数。如果需要,您还可以重写它们(多亏了virtual关键字,当使用指向Carrot对象的Plant指针时,派生类的实现将被调用)。

注意,如果你想确保永远不会实例化一个Plant对象,你应该使任何非通用函数(如DoSomethingTypeSpecific(),胡萝卜或花会做不同的事情)纯虚,并通过创建一个抽象基类。所有的基类都有来实现这些函数。这里的

内联没有真正的区别,它只是在头文件或单独的.cpp文件中定义函数的问题。一般来说,将实现保存在一个单独的文件中是个好主意,但如果你愿意,这些小的setter和getter可以很容易地内联。

您可以通过在类声明中添加方法来纠正错误:

class Carrot : public Plant
{
public:
   Carrot();
   ~Carrot();
  virtual std::string getPlantName();
private:
  std::string _plantName;
}; 

或者,如果所有植物都有名称,则可以在Plant类中定义方法(可能在in Plant .cpp中)。事实上,你必须定义它,除非你声明它是纯虚的。

你需要声明函数

class Carrot : public Plant
{
public:
    Carrot();
    ~Carrot();
    std::string getPlantName(); //Add this
private:
    std::string _plantName;
};

注意事项:

    Carrot::getPlantName不是必须是虚拟的,尽管许多c++开发人员认为这是一种很好的形式。我个人更喜欢只在抽象基类中使用虚拟,而在具体类中不使用虚拟
  • 您可能需要将virtual ~Plant() {}添加到Plant类中。几乎总是希望带有虚方法的类也具有虚析构函数。