派生类使用抽象类的方法

时间:2019-04-09 13:23:12

标签: c++

我有一个类似于下面的抽象基类:

class AbstractClass {
public:
    virtual ~AbstractClass() = 0 {}
    std::string GetName() const { return m_Name; }
private:
    std::string m_Name;
};

现在我有很多派生类,我想像这样实现它们

class DerivedClass1 : public AbstractClass{
public:
    DerivedClass1() = default;
    ~DerivedClass1() = default;
private:
    std::string m_Name = "DerivedClass1";
};


int main() {
    DerivedClass1 class1;
    std::cout << class1.GetName();

    return 0;
}

我不想每次派生Class时都重写GetName(),这可能吗? 编辑: 我收到了链接器错误。错误LNK2019。

4 个答案:

答案 0 :(得分:2)

在基类中仅使用一个名称,并使用带有参数的构造函数:

class AbstractClass{
public:
   AbstractClass(const std::string& name) : m_Name(name){}
   std::string GetName() const { return m_Name; }
private:
   std::string m_Name;
};



DerivedClass1 : public AbstractClass{
public:
   DerivedClass() : AbstractClass("DerivedClass1") {}
};


int main(){
   DerivedClass1 class1;
   std::cout << class1.GetName();

    return 0;
}

似乎没有理由将基类抽象化,但是如果您这样做需要这样做,那么即使是纯虚拟析构函数也必须具有定义,否则您将得到链接器错误,因为它是销毁派生对象时需要。
另外,如果析构函数不存在,m_Name何时会被销毁?

class Abstract
{
public: 
    virtual ~Abstract() = 0;
};

Abstract::~Abstract() {}

这使一个无法实例化的类,但其派生类仍然可以被销毁。

答案 1 :(得分:1)

这不是您“替代” GetName()的方式。您可以将GetName()虚拟化并在派生类中覆盖它:

class AbstractClass {
public:
   virtual ~AbstractClass() = default;
   virtual std::string GetName() const { return "AbstractClass"; }
private:
   std::string m_Name;
};

和:

class DerivedClass1 : public AbstractClass {
public:
   DerivedClass() = default;
   std::string GetName() const override { return "DerivedClass1"; }
};

或者您可以通过将其传递给基类构造函数来在派生类中设置m_Name

class AbstractClass {
public:
   AbstractClass(const std::string& name) : m_Name(name) {}
   virtual ~AbstractClass() = default;
   std::string GetName() const { return m_Name; }
protected: // protected not private
   std::string m_Name;
};

和:

class DerivedClass1 : public AbstractClass {
public:
   DerivedClass() : AbstractClass("DerivedClass1") {}
};

或者您可以在派生类的构造函数中对其进行设置:

class AbstractClass {
public:
   virtual ~AbstractClass() = default;
   std::string GetName() const { return m_Name; }
protected: // protected not private
   std::string m_Name;
};

和:

class DerivedClass1 : public AbstractClass {
public:
   DerivedClass() : AbstractClass() { m_Name = "DerivedClass1"; }
};

答案 2 :(得分:0)

您会收到链接错误,因为AbstractClass的析构函数即使为空也需要定义。

AbstractClass::~AbstractClass()
{
  // Compulsory virtual destructor definition,
  // even if it's empty
}

LIVE on Wandbox

关于覆盖getName:您不必这样做。如果未在派生类中提供实现,则使用继承的一个。

答案 3 :(得分:0)

代码表示问题在于如何获取类名?但这并没有明确说明问题(XY问题)

如何处理类名?

您可以使用RTTI:

class ClassName {
public:
    virtual ~ClassName() {} // just to enable RTTI for all decendants

    std::string getClassName() {
        return typeid(*this).name();
    }
};

https://wandbox.org/permlink/LvPdA37arMr0LFQW

但是您可以看到它添加了一些额外的前缀(取决于编译器)。 Boost可以清理它:

https://wandbox.org/permlink/8XiB7yVOM0wYVxpl