我正在实现一个通用接口,它可以桥接某些基类的不同实现。
接口实用程序如下所示:
// InterfaceUtils.h
//
// Base object class
class IBaseObject {
virtual ~IBaseObject() = default;
};
// Unknown object adapter
class UnknownObject
{
public:
UnknownObject() = default;
UnknownObject(const UnknownObject& from);
UnknownObject(UnknownObject&& from) noexcept;
explicit UnknownObject(const IBaseObject& from);
explicit UnknownObject(IBaseObject* from)
{
SetPointer(from);
}
virtual ~UnknownObject()
{
DeletePointer();
}
template<class Interface>
const Interface* RetrieveInterface() const
{
if (!m_pObject)
return nullptr;
return dynamic_cast<const Interface*>(m_pObject);
}
template<class Interface>
Interface* RetrieveInterface()
{
if (!m_pObject)
return nullptr;
return dynamic_cast<Interface*>(m_pObject);
}
UnknownObject& operator=(const UnknownObject& other);
UnknownObject& operator=(UnknownObject&& other) noexcept;
[[nodiscard]] bool IsNull() const
{
return m_pObject == nullptr;
}
void SetNull();
protected:
[[nodiscard]] virtual const IBaseObject* GetPointer() const
{
return m_pObject;
}
virtual IBaseObject* GetPointer()
{
return m_pObject;
}
void SetPointer(ISymplektBaseObject* pObject)
{
m_pObject = pObject;
}
void DeletePointer() const
{
// Q: Unsafe for memory leaks ?
// delete m_pObject;
}
private:
//>! stored pointer to object
IBaseObject* m_pObject = nullptr;
};
// Generic object interface template
template <class Interface>
class ObjectInterface : public UnknownObject
{
public:
explicit ObjectInterface(const IBaseObject& other)
: UnknownObject(other) { }
explicit ObjectInterface(IBaseObject* other)
: UnknownObject(other) { }
explicit ObjectInterface(const UnknownObject& other)
: UnknownObject(other.RetrieveInterface<Interface>() != nullptr ? other : UnknownObject()) { }
explicit ObjectInterface(UnknownObject&& other) noexcept
: UnknownObject(other.RetrieveInterface<Interface>() != nullptr ? std::move(other) : UnknownObject()) { }
ObjectInterface(const ObjectInterface<Interface>& other)
: UnknownObject(other) { }
ObjectInterface(ObjectInterface<Interface>&& other) noexcept
: UnknownObject(std::move(other)) { }
~ObjectInterface() override
{
UnknownObject::~UnknownObject();
}
ObjectInterface& operator=(const ObjectInterface<Interface>& other)
{
return UnknownObject::operator=(other);
}
Interface* operator->()
{
return GetInterface();
}
const Interface* operator->() const
{
return GetInterface();
}
Interface* GetInterface()
{
return RetrieveInterface<Interface>();
}
const Interface* GetInterface() const
{
return RetrieveInterface<Interface>();
}
};
如果有用的话,我还会编写*.cpp:的内容
// InterfaceUtils.cpp
//
#include "InterfaceUtils.h"
void UnknownObject::DeleteInterface(UnknownObject& obj)
{
if (obj.IsNull())
return;
obj.SetNull();
}
UnknownObject::UnknownObject(const UnknownObject& from)
{
if (auto* fromObj = from.GetPointer(); fromObj != nullptr)
{
SetPointer(const_cast<IBaseObject*>(fromObj));
return;
}
SetPointer(nullptr);
}
UnknownObject::UnknownObject(UnknownObject&& from) noexcept
{
SetPointer(from.GetPointer());
from.SetPointer(nullptr);
}
UnknownObject::UnknownObject(const IBaseObject& from)
{
auto* pObject = &from;
SetPointer(const_cast<IBaseObject*>(pObject));
}
UnknownObject& UnknownObject::operator=(const UnknownObject& other)
{
if (this == &other)
return *this;
if (auto* fromObj = other.GetPointer(); fromObj != nullptr)
SetPointer(const_cast<IBaseObject*>(fromObj));
else
SetPointer(nullptr);
return *this;
}
UnknownObject& UnknownObject::operator=(UnknownObject&& other) noexcept
{
DeletePointer();
SetPointer(other.GetPointer());
other.SetPointer(nullptr);
return *this;
}
void UnknownObject::SetNull()
{
DeletePointer();
m_pObject = nullptr;
}
类IBaseObject
、UnknownObject
和ObjectInterface<>
的目的是能够将IBaseObject
扩展到不同的实现,例如:
class ITestClass : public IBaseObject
{
public:
ITestClass() : IBaseObject() {}
ITestClass(const double& val)
: IBaseObject(), m_Value(val) { }
void SetValue(const double& val)
{
m_Value = val;
}
[[nodiscard]] double GetValue() const
{
return m_Value;
}
[[nodiscard]] virtual double ProcessValue() const = 0;
protected:
double m_Value = 0.0;
};
//
// test class implementation returning m_Value^2 with ProcessValue
//
class TestClassSquareImpl : public ITestClass
{
public:
~TestClassSquareImpl() override
{}
TestClassSquareImpl(const double& val)
: ITestClass(val) {}
[[nodiscard]] double ProcessValue() const override
{
return m_Value * m_Value;
}
};
//
// test class implementation returning sqrt(m_Value) with ProcessValue
//
class TestClassSqrtImpl : public ITestClass
{
public:
~TestClassSqrtImpl() override
{}
TestClassSqrtImpl(const double& val)
: ITestClass(val)
{
}
[[nodiscard]] double ProcessValue() const override
{
return sqrt(m_Value);
}
};
使用如下:
const double dataValue = 3.0;
const auto testObjSqr = TestClassSquareImpl(dataValue);
const auto testObjSqrt = TestClassSqrtImpl(dataValue);
const auto iTestObjSqr = ObjectInterface<ITestClass>(testObjSqr);
const auto iTestObjSqrt = ObjectInterface<ITestClass>(testObjSqrt);
std::cout << iTestObjSqr->ProcessValue() << "n"; // out: 9.0
std::cout << iTestObjSqrt->ProcessValue() << "n"; // out: 1.73205080...
问题是:根据我以前的经验,方法UnknownObject::DeletePointer
应该删除原始m_pObject
以避免内存泄漏,但当它删除时,会引发异常,因为派生实例的内存块即将释放。不删除m_pObject
指针是否安全?UnknownObject
被销毁后,它会被删除吗?
inb4:我已经尝试过使用std::unique_ptr
和std::shared_ptr
,导致无法访问派生实现(例如TestClassSquareImpl::ProcessValue
或ITestClass::GetValue
(中的方法。
编辑:free
抛出的异常为:Invalid address specified to RtlValidateHeap( 0000016F756B0000, 00000004B0AFF988 )
。我第一次遇到它是在gtest中运行一个示例时,但每当程序超出范围时,也会发生同样的事情,导致DeletePointer
调用。
我接受了@Frank的建议,删除了const_cast
并实现了一个Clone
方法,该方法具有抽象声明:
[[nodiscard]] virtual IBaseObject* Clone() const = 0;
在IBaseObject
中,必须在派生类中实现:
[[nodiscard]] IBaseObject* Clone() const override
{
return (new TestClassSquareImpl(*this));
}
类似地在CCD_ 19中。Clone
方法在副本构造和副本分配中是必需的(每当访问和复制具有其自身实例的不同接口或不同实例本身时,例如:SetPointer(fromObj->Clone());
(
此外,导致重复删除
~ObjectInterface() override
{
UnknownObject::~UnknownObject();
}
调用其基析构函数。
通过这些调整,delete m_pObject
不会投掷。
需要注意的是,放置std::shared_ptr<IBaseObject> m_pObject;
将访问任何成员的范围限制为IBaseObject
成员。如果我错了,请纠正我,但在这种情况下,m_Value
需要定义为IBaseObject
中的字段
非常感谢您的真知灼见。
编辑:我发现我在重新发明轮子。专门的STL转换可以很容易地执行测试示例中的下转换:
#include <iostream>
#include <memory>
#include <cmath>
class Base
{
public:
Base(const double value)
: m_Value(value) {}
double& GetValue()
{
return m_Value;
}
void SetValue(const double value)
{
m_Value = value;
}
[[nodiscard]] virtual double ProcessValue() const = 0;
protected:
double m_Value{ 0.0 };
};
class DerivedA : public Base
{
public:
DerivedA(const double value)
: Base(value) {}
[[nodiscard]] double ProcessValue() const override
{
return m_Value * m_Value + m_SpecializedValueForA;
}
private:
double m_SpecializedValueForA = 1.0;
};
class DerivedB : public Base
{
public:
DerivedB(const double value)
: Base(value) {}
[[nodiscard]] double ProcessValue() const override
{
return sqrt(m_Value) + m_SpecializedValueForB;
}
private:
double m_SpecializedValueForB = -1.0;
};
enum class [[nodiscard]] ImplementationType
{
A = 0,
B = 1
};
class BaseWithSwitchableImplementation
{
public:
BaseWithSwitchableImplementation(const double value, const ImplementationType type)
{
InternalSetAndInitImplementationWithValue(type, value);
}
[[nodiscard]] double ProcessValue() const
{
return m_Impl->ProcessValue();
}
void SetAndInitImplementationWithValue(const ImplementationType type, const double value)
{
if (type == m_ImplType)
return; // nothing happens
InternalSetAndInitImplementationWithValue(type, value);
}
private:
void InternalSetAndInitImplementationWithValue(const ImplementationType type, const double value)
{
m_ImplType = type;
m_Impl = nullptr;
if (type == ImplementationType::A)
{
const auto implAPtr = std::make_shared<DerivedA>(DerivedA(value));
m_Impl = std::static_pointer_cast<Base>(implAPtr);
}
else if (type == ImplementationType::B)
{
const auto implBPtr = std::make_shared<DerivedB>(DerivedB(value));
m_Impl = std::static_pointer_cast<Base>(implBPtr);
}
else
{
std::cout << "ERROR: Invalid ImplementationType!n";
}
}
std::shared_ptr<Base> m_Impl;
ImplementationType m_ImplType;
};
int main()
{
const double value = 3.0;
const auto instanceA = std::make_shared<DerivedA>(DerivedA(value));
const auto instanceB = std::make_shared<DerivedB>(DerivedB(value));
const auto basePtrA = std::static_pointer_cast<Base>(instanceA);
const auto basePtrB = std::static_pointer_cast<Base>(instanceB);
std::cout << "basePtrA->ProcessValue() = " << basePtrA->ProcessValue() << "n";
std::cout << "basePtrB->ProcessValue() = " << basePtrB->ProcessValue() << "n";
const auto switchableImplA = BaseWithSwitchableImplementation(value, ImplementationType::A);
const auto switchableImplB = BaseWithSwitchableImplementation(value, ImplementationType::B);
std::cout << "switchableImplA.ProcessValue() = " << switchableImplA.ProcessValue() << "n";
std::cout << "switchableImplA.ProcessValue() = " << switchableImplB.ProcessValue() << "n";
auto switchableImplAToB = BaseWithSwitchableImplementation(value, ImplementationType::A);
std::cout << "switchableImplAToB.ProcessValue() = " << switchableImplAToB.ProcessValue() << "n";
switchableImplAToB.SetAndInitImplementationWithValue(ImplementationType::B, value);
std::cout << "switchableImplAToB.ProcessValue() = " << switchableImplAToB.ProcessValue() << "n";
return 0;
}
输出:
basePtrA->ProcessValue() = 10
basePtrB->ProcessValue() = 0.732051
switchableImplA.ProcessValue() = 10
switchableImplA.ProcessValue() = 0.732051
switchableImplAToB.ProcessValue() = 10
switchableImplAToB.ProcessValue() = 0.732051
这正是我所需要的。