[英]"One or more multiply defined symbols found". Static and friend function
I'm trying to use interface
classes and I have the following class
structure:我正在尝试使用interface
类,并且我有以下class
结构:
IBase.h: IBase.h:
#pragma once
class IBase
{
protected:
virtual ~IBase() = default;
public:
virtual void Delete() = 0;
IBase& operator=(const IBase&) = delete;
};
IQuackable.h: IQuackable.h:
#ifndef IQUACKABLE
#define IQUACKABLE
#include "IBase.h"
#include <iostream>
class IQuackable : public IBase
{
protected:
IQuackable() = default;
~IQuackable() = default;
public:
virtual void Quack() = 0;
static IQuackable* CreateInstance();
};
#endif //
MallardDuck.h:野鸭鸭.h:
#pragma once
#include "IQuackable.h"
class MallardDuck : public IQuackable
{
private:
MallardDuck();
protected:
~MallardDuck();
public:
void Delete() override;
void Quack() override;
friend IQuackable* IQuackable::CreateInstance();
};
MallardDuck.cpp:野鸭鸭.cpp:
#include "MallardDuck.h"
MallardDuck::MallardDuck() {}
MallardDuck::~MallardDuck() {}
void MallardDuck::Delete() { delete this; }
void MallardDuck::Quack()
{
std::cout << "Quack!\n";
}
IQuackable* IQuackable::CreateInstance()
{
return static_cast<IQuackable*>(new MallardDuck());
}
Also I've created class RedHeadDuck.h and.cpp with the same declaration and definition as MallardDuck.我还创建了 class RedHeadDuck.h 和.cpp,其声明和定义与 MallardDuck 相同。
And, finaly, main class code:最后,主要的 class 代码:
#include "MallardDuck.h"
#include "RedHeadDuck.h"
int main()
{
IQuackable* mallardDuck = MallardDuck::CreateInstance();
IQuackable* redHeadDuck = RedHeadDuck::CreateInstance();
mallardDuck->Quack();
redHeadDuck->Quack();
}
And here I got two errors:在这里我遇到了两个错误:
LNK2005 "public: static class IQuackable * __cdecl IQuackable::CreateInstance(void)" (?CreateInstance@IQuackable@@SAPAV1@XZ) already defined in MallardDuck.obj". LNK2005“公共:static class IQuackable * __cdecl IQuackable::CreateInstance(void)”(?CreateInstance@IQuackable@@SAPAV1@XZ) 已在 MallardDuck.obj 中定义。
LNK1169 "one or more multiply defined symbols found". LNK1169“找到一个或多个多重定义的符号”。
As I find out, the problem is in double definition, but how it fix?我发现,问题出在双重定义上,但它是如何解决的呢?
I've read about Header guards, but, as I understood, it can't help in this case.我读过有关 Header 防护装置的信息,但据我了解,在这种情况下它无济于事。 Also people write about inline functions, but I've not realized how it may be used here.人们也写了关于内联函数的文章,但我还没有意识到如何在这里使用它。
What can I do?我能做些什么?
I suppose these are what you are trying to obtain by adopting all the complicated patterns:我想这些是你试图通过采用所有复杂模式来获得的:
Delete()
method通过实现Delete()
方法来处理 dtorsThere are at least 3 ways to meet requirement 1-3, as explained below:至少有 3 种方法可以满足要求 1-3,如下所述:
This is the easiest way, and it's fully capable of current main.cpp
.这是最简单的方法,它完全能够处理当前的main.cpp
。 Derived classes can override static methods of their base class.派生类可以覆盖其基础 class 的 static 方法。
In file MallardDuck.h
and RedHeadDuck.h
:在文件MallardDuck.h
和RedHeadDuck.h
:
// Replace this:
// friend IQuackable* IQuackable::CreateInstance();
// With this:
static IQuackable* CreateInstance();
In file MallardDuck.cpp
(and RedHeadDuck.cpp
similarly):在文件MallardDuck.cpp
(和RedHeadDuck.cpp
类似)中:
// Replace this:
// IQuackable* IQuackable::CreateInstance() {
// return static_cast<IQuackable*>(new MallardDuck());
// }
// With this:
IQuackable* MallardDuck::CreateInstance() {
return new MallardDuck();
}
The problem with this is that: other derived classes that don't override and hide CreateInstance()
will still expose IQuackable::CreateInstance()
as a "fallback".这样做的问题是:其他不覆盖和隐藏CreateInstance()
的派生类仍会将IQuackable::CreateInstance()
公开为“后备”。 Thus:因此:
IQuackable::CreateInstance()
(so far, you don't have to), then once it is called via a derived class, the code won't compile and won't give a reason that's comprehensible to others;如果您实际上没有实现IQuackable::CreateInstance()
(到目前为止,您不必),那么一旦通过派生的 class 调用它,代码将无法编译并且不会给出可理解的原因对他人; or或者nullptr
or something, which is the worst practice in C++ (that's what we do in C since it has no language-level support for error handling; any C++ function that cannot fulfill its job should never return). otherwise you would have to return a nullptr
or something, which is the worst practice in C++ (that's what we do in C since it has no language-level support for error handling; any C++ function that cannot fulfill its job should never return).Either way is not elegant.无论哪种方式都不优雅。
This pattern requires a cooperating "factory class", which is abstract;这种模式需要一个协作的“工厂类”,它是抽象的; then whenever you derive a concrete quackable, derive also its factory.那么每当你派生出一个具体的 quackable 时,也要派生出它的工厂。
In your case you'll need to sketch out a IQuackableFactory
, exposing IQuackableFactory::CreateInstance()
, then derive a MallardDuckFactory
and a RedHeadDuckFactory
.在您的情况下,您需要绘制一个IQuackableFactory
,公开IQuackableFactory::CreateInstance()
,然后派生一个MallardDuckFactory
和一个RedHeadDuckFactory
。
There are plenty of good examples already, so I won't demonstrate here.已经有很多很好的例子,所以我不会在这里演示。
There's yet another way of doing things.还有另一种做事方式。 By CreateInstance()
you're actually providing a "Give me an instance of this class."通过CreateInstance()
,您实际上是在提供“给我这个 class 的实例”。 feature.特征。 Typically we use the CRTP ( curiously recurring template pattern ) to "inject" a certain feature into a class.通常我们使用 CRTP( 奇怪的重复模板模式)将某个特征“注入”到 class 中。
First write this file EnableCreateInstance.hpp
:首先编写这个文件EnableCreateInstance.hpp
:
#ifndef _ENABLECREATEINSTANCE_HPP_
#define _ENABLECREATEINSTANCE_HPP_
template <class T>
struct EnableCreateInstance {
static T* CreateInstance() { return new T(); }
};
#endif //_ENABLECREATEINSTANCE_HPP_
Then in MallardDuck.h
:然后在MallardDuck.h
中:
// Add:
#include "EnableCreateInstance.hpp"
class MallardDuck : public IQuackable, public EnableCreateInstance<MallardDuck> {
private:
MallardDuck();
friend class EnableCreateInstance<MallardDuck>;
...
In file RedHeadDuck.h
do the similar: include header, publicly inherit EnableCreateInstance<RedHeadDuck>
, and declare EnableCreateInstance<RedHeadDuck>
as friend class.在文件RedHeadDuck.h
中执行类似操作:包含 header,公开继承EnableCreateInstance<RedHeadDuck>
,并将EnableCreateInstance<RedHeadDuck>
声明为朋友 class。
This provides more flexibility: you're still providing an interface CreateInstance()
, but in a less "aggressive" way: derived classes have their freedom to choose whether or not to provide CreateInstance()
.这提供了更大的灵活性:您仍然提供接口CreateInstance()
,但以一种不那么“激进”的方式:派生类可以自由选择是否提供CreateInstance()
。 If they do, just inherit and (if ctor made private) declare friendship;如果他们这样做,只需继承并(如果 ctor 设为私有)声明友谊; if not, omit the additional inheritance.如果没有,请省略额外的 inheritance。
Well, actually you can use delete this
in non-static non-dtor method.好吧,实际上您可以在非静态非 dtor方法中使用delete this
。 But:但:
So, we seldom provide such "deleters" in modern C++.因此,我们很少在现代 C++ 中提供这样的“删除器”。 You can get all the benefits it may provide through smart pointers , plus the ability to avoid UBs and so much more.您可以通过智能指针获得它可能提供的所有好处,以及避免 UB 的能力等等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.