我有一个类似于下面的抽象基类:
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。
答案 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
}
关于覆盖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可以清理它: