Polymorphic clone for CRT Pattern in templates (basically a static_cast for concrete initializations of template class)

This commit is contained in:
Klaus Basan
2013-04-27 17:18:32 +02:00
parent b257862aac
commit c97ddc4e3b
8 changed files with 248 additions and 244 deletions

View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2013 VATSIM Community / authors /* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@@ -58,6 +58,14 @@ public:
*/ */
CCoordinateNed(const CCoordinateGeodetic &referencePosition, double north, double east, double down) : CVector3DBase(north, east, down), m_referencePosition(referencePosition), m_hasReferencePosition(true) {} CCoordinateNed(const CCoordinateGeodetic &referencePosition, double north, double east, double down) : CVector3DBase(north, east, down), m_referencePosition(referencePosition), m_hasReferencePosition(true) {}
/*!
* \brief Constructor by values
* \param north
* \param east
* \param down
*/
CCoordinateNed(double north, double east, double down) : CVector3DBase(north, east, down), m_referencePosition(), m_hasReferencePosition(false) {}
/*! /*!
* \brief Copy constructor * \brief Copy constructor
* \param otherNed * \param otherNed

View File

@@ -1,15 +0,0 @@
#include "geolatitude.h"
namespace BlackMisc
{
namespace Geo
{
// see here for the reason of thess forward instantiations
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
// template class CGeoLatLonBase<CGeoLatitude>;
}
}

View File

@@ -27,199 +27,200 @@
namespace BlackMisc namespace BlackMisc
{ {
CLog::CLog(IContext &context, TLogType logType) : m_context(context), m_logType(logType) CLog::CLog(IContext &context, TLogType logType) : m_context(context), m_logType(logType)
{
}
CLog::~CLog(void)
{
}
void CLog::printWithNewLine(QString &message)
{
//! If we have no displays, we have nothing to do.
if (hasNoDisplays())
{ {
return;
} }
CLog::~CLog(void) QChar newLine = '\n';
//! We should print the message with a new line. So check
//! if one is already there. If not append it.
if (!message.endsWith(newLine, Qt::CaseInsensitive))
message.append(newLine);
printString(message);
}
void CLog::print(QString &message)
{
//! If we have no displays, we have nothing to do.
if (hasNoDisplays())
{ {
return;
} }
void CLog::printWithNewLine(QString &message) printString(message);
}
void CLog::printString(QString &message)
{
QString logDisplay;
//! Just in case, lets set the default name
m_context.setDefaultApplicationName();
//! If the current line is empty, then put some information as
//! the prefix.
//! Be aware: This information must be set by the \sa setLogInformation()
//! before.
if (m_logLine.isEmpty())
{ {
//! If we have no displays, we have nothing to do. m_logInformation.m_dateTime = QDateTime::currentDateTime();
if (hasNoDisplays()) m_logInformation.m_logType = m_logType;
m_logInformation.m_applicationName = m_context.getApplicationName();
m_logInformation.m_threadId = 0; //getThreadId();
m_logInformation.m_sourceFile = m_sourceFile;
m_logInformation.m_line = m_line;
m_logInformation.m_methodName = m_methodName;
m_logLine = message;
}
else
{
m_logLine += message;
}
//! If this is not the end of the line, we are done for now.
if (! message.contains('\n'))
{
return;
}
for (TLogDisplayList::iterator it = m_logDisplays.begin(); it != m_logDisplays.end(); ++it)
{
(*it)->print(m_logInformation, m_logLine);
}
//! Reset everything for the next line
m_logLine.clear();
resetLogInformation();
}
void CLog::attachDisplay(ILogDisplay *display)
{
//! Display must be a valid pointer
if (display == NULL)
{
printf("Trying to add a NULL pointer\n");
return;
}
//! Check if it is already attached
if (!m_logDisplays.contains(display))
{
m_logDisplays.push_back(display);
}
else
{
bWarning(m_context) << "Couldn't attach the display - already in the list!";
}
}
ILogDisplay *CLog::getDisplay(const QString &displayName)
{
//! Must be a valid name
if (displayName.isEmpty())
{
bWarning(m_context) << "Cannot return a display with empty name!";
return NULL;
}
TLogDisplayList::const_iterator it;
//! Loop through the list and find the candidate
for (it = m_logDisplays.constBegin(); it != m_logDisplays.constEnd(); ++it)
{
//! Does it have the desired name?
if ((*it)->DisplayName == displayName)
{ {
return; return *it;
} }
}
return NULL;
}
QChar newLine = '\n'; void CLog::dettachDisplay(ILogDisplay *logDisplay)
{
//! We should print the message with a new line. So check //! Must be a valid pointer
//! if one is already there. If not append it. if (logDisplay == NULL)
if (!message.endsWith(newLine, Qt::CaseInsensitive)) {
message.append(newLine); bWarning(m_context) << "Cannot remove a NULL displayer!";
return;
printString(message);
} }
void CLog::print(QString &message) //! We should have only one, but just in case.
{ m_logDisplays.removeAll(logDisplay);
//! If we have no displays, we have nothing to do.
if (hasNoDisplays())
{
return;
}
printString(message); }
void CLog::dettachDisplay(const QString &displayName)
{
//! Must be a valid name
if (displayName.isEmpty())
{
bWarning(m_context) << "Cannot remove displayer with empty name!";
return;
} }
void CLog::printString(QString &message) TLogDisplayList::iterator it;
for (it = m_logDisplays.begin(); it != m_logDisplays.end();)
{ {
QString logDisplay; if ((*it)->DisplayName == displayName)
//! Just in case, lets set the default name
m_context.setDefaultApplicationName();
//! If the current line is empty, then put some information as
//! the prefix.
//! Be aware: This information must be set by the \sa setLogInformation()
//! before.
if (m_logLine.isEmpty())
{ {
m_logInformation.m_dateTime = QDateTime::currentDateTime(); it = m_logDisplays.erase(it);
m_logInformation.m_logType = m_logType;
m_logInformation.m_applicationName = m_context.getApplicationName();
m_logInformation.m_threadId = 0; //getThreadId();
m_logInformation.m_sourceFile = m_sourceFile;
m_logInformation.m_line = m_line;
m_logInformation.m_methodName = m_methodName;
m_logLine = message;
} }
else else
{ {
m_logLine += message; ++it;
} }
//! If this is not the end of the line, we are done for now.
if (! message.contains('\n'))
{
return;
}
for (TLogDisplayList::iterator it = m_logDisplays.begin(); it != m_logDisplays.end(); ++it)
{
(*it)->print(m_logInformation, m_logLine);
}
//! Reset everything for the next line
m_logLine.clear();
resetLogInformation();
} }
}
void CLog::attachDisplay(ILogDisplay *display) bool CLog::isAttached(ILogDisplay *logDisplay) const
{
return m_logDisplays.contains(logDisplay);
}
void CLog::setLogInformation(int line, const char *sourceFile, const char *methodName)
{
//! We have to make sure, we at least one display.
if (!hasNoDisplays())
{ {
//! Display must be a valid pointer m_mutex.lock();
if (display == NULL) m_posSet++;
{ m_sourceFile = sourceFile;
printf("Trying to add a NULL pointer\n"); m_line = line;
return; m_methodName = methodName;
}
//! Check if it is already attached
if (!m_logDisplays.contains(display))
{
m_logDisplays.push_back(display);
}
else
{
bWarning(m_context) << "Couldn't attach the display - already in the list!";
}
} }
}
ILogDisplay *CLog::getDisplay(const QString &displayName) void CLog::resetLogInformation()
{
//! It should be impossible that this gets called, withoud
//! having a attached display.
Q_ASSERT(!hasNoDisplays());
if (m_posSet > 0)
{ {
//! Must be a valid name m_sourceFile = NULL;
if (displayName.isEmpty()) m_line = -1;
{ m_methodName = NULL;
bWarning(m_context) << "Cannot return a display with empty name!"; m_posSet--;
return NULL; m_mutex.unlock();
}
TLogDisplayList::const_iterator it;
//! Loop through the list and find the candidate
for (it = m_logDisplays.constBegin(); it != m_logDisplays.constEnd(); ++it)
{
//! Does it have the desired name?
if ((*it)->DisplayName == displayName)
{
return *it;
}
}
}
void CLog::dettachDisplay(ILogDisplay *logDisplay)
{
//! Must be a valid pointer
if (logDisplay == NULL)
{
bWarning(m_context) << "Cannot remove a NULL displayer!";
return;
}
//! We should have only one, but just in case.
m_logDisplays.removeAll(logDisplay);
}
void CLog::dettachDisplay(const QString &displayName)
{
//! Must be a valid name
if (displayName.isEmpty())
{
bWarning(m_context) << "Cannot remove displayer with empty name!";
return;
}
TLogDisplayList::iterator it;
for (it = m_logDisplays.begin(); it != m_logDisplays.end();)
{
if ((*it)->DisplayName == displayName)
{
it = m_logDisplays.erase(it);
}
else
{
++it;
}
}
}
bool CLog::isAttached(ILogDisplay *logDisplay) const
{
return m_logDisplays.contains(logDisplay);
}
void CLog::setLogInformation(int line, const char *sourceFile, const char *methodName)
{
//! We have to make sure, we at least one display.
if (!hasNoDisplays())
{
m_mutex.lock();
m_posSet++;
m_sourceFile = sourceFile;
m_line = line;
m_methodName = methodName;
}
}
void CLog::resetLogInformation()
{
//! It should be impossible that this gets called, withoud
//! having a attached display.
Q_ASSERT(!hasNoDisplays());
if (m_posSet > 0)
{
m_sourceFile = NULL;
m_line = -1;
m_methodName = NULL;
m_posSet--;
m_mutex.unlock();
}
} }
}
} // namespace BlackMisc } // namespace BlackMisc

View File

@@ -31,6 +31,15 @@ protected:
*/ */
QString stringForConverter() const; QString stringForConverter() const;
/*!
* \brief Clone as conrete implementation
* \return
*/
ImplMatrix clone() const
{
return static_cast<ImplMatrix const &>(*this);
}
public: public:
/*! /*!
* \brief Default constructor * \brief Default constructor
@@ -109,8 +118,7 @@ public:
*/ */
ImplMatrix operator *(double factor) const ImplMatrix operator *(double factor) const
{ {
ImplMatrix m; ImplMatrix m = this->clone();
m += (*this);
m *= factor; m *= factor;
return m; return m;
} }
@@ -151,8 +159,7 @@ public:
*/ */
ImplMatrix operator /(double factor) const ImplMatrix operator /(double factor) const
{ {
ImplMatrix m(0); ImplMatrix m = this->clone();
m += (*this);
m /= factor; m /= factor;
return m; return m;
} }
@@ -175,8 +182,7 @@ public:
*/ */
ImplMatrix operator +(const ImplMatrix &otherMatrix) const ImplMatrix operator +(const ImplMatrix &otherMatrix) const
{ {
ImplMatrix m(0); ImplMatrix m = this->clone();
m += (*this);
m += otherMatrix; m += otherMatrix;
return m; return m;
} }
@@ -199,8 +205,7 @@ public:
*/ */
ImplMatrix operator -(const ImplMatrix &otherMatrix) const ImplMatrix operator -(const ImplMatrix &otherMatrix) const
{ {
ImplMatrix m(0); ImplMatrix m = this->clone();
m += (*this);
m -= otherMatrix; m -= otherMatrix;
return m; return m;
} }
@@ -220,9 +225,7 @@ public:
*/ */
bool isIdentityEpsilon() const bool isIdentityEpsilon() const
{ {
ImplMatrix m(0.0); ImplMatrix m = this->clone().round();
m += (*this);
m.round();
return m.isIdentity(); return m.isIdentity();
} }
@@ -257,9 +260,7 @@ public:
*/ */
bool isZeroEpsilon() const bool isZeroEpsilon() const
{ {
ImplMatrix m(0.0); ImplMatrix m = this->clone().round();
m += (*this);
m.round();
return m.isZero(); return m.isZero();
} }
@@ -277,6 +278,7 @@ public:
/*! /*!
* \brief Round all values * \brief Round all values
* \return
*/ */
ImplMatrix &round(); ImplMatrix &round();

View File

@@ -16,7 +16,7 @@ namespace Math
/* /*
* Convert to string * Convert to string
*/ */
template <class ImplClass> QString CVector3DBase<ImplClass>::stringForConverter() const template <class ImplVector> QString CVector3DBase<ImplVector>::stringForConverter() const
{ {
QString s = ("{%1, %2, %3}"); QString s = ("{%1, %2, %3}");
s = s.arg(QString::number(this->m_i, 'f')). s = s.arg(QString::number(this->m_i, 'f')).
@@ -28,7 +28,7 @@ template <class ImplClass> QString CVector3DBase<ImplClass>::stringForConverter(
/* /*
* Vector to zero * Vector to zero
*/ */
template <class ImplClass> void CVector3DBase<ImplClass>::setZero() template <class ImplVector> void CVector3DBase<ImplVector>::setZero()
{ {
this->fill(0.0); this->fill(0.0);
} }
@@ -36,7 +36,7 @@ template <class ImplClass> void CVector3DBase<ImplClass>::setZero()
/* /*
* Vector to zero * Vector to zero
*/ */
template <class ImplClass> void CVector3DBase<ImplClass>::fill(double value) template <class ImplVector> void CVector3DBase<ImplVector>::fill(double value)
{ {
this->m_i = value; this->m_i = value;
this->m_j = value; this->m_j = value;
@@ -46,7 +46,7 @@ template <class ImplClass> void CVector3DBase<ImplClass>::fill(double value)
/* /*
* Element * Element
*/ */
template <class ImplClass> double CVector3DBase<ImplClass>::getElement(size_t row) const template <class ImplVector> double CVector3DBase<ImplVector>::getElement(size_t row) const
{ {
double d; double d;
switch (row) switch (row)
@@ -71,7 +71,7 @@ template <class ImplClass> double CVector3DBase<ImplClass>::getElement(size_t ro
/* /*
* Set given element * Set given element
*/ */
template <class ImplClass> void CVector3DBase<ImplClass>::setElement(size_t row, double value) template <class ImplVector> void CVector3DBase<ImplVector>::setElement(size_t row, double value)
{ {
switch (row) switch (row)
{ {
@@ -94,9 +94,9 @@ template <class ImplClass> void CVector3DBase<ImplClass>::setElement(size_t row,
/* /*
* Cross product * Cross product
*/ */
template <class ImplClass> ImplClass CVector3DBase<ImplClass>::crossProduct(const ImplClass &otherVector) const template <class ImplVector> ImplVector CVector3DBase<ImplVector>::crossProduct(const ImplVector &otherVector) const
{ {
ImplClass v(otherVector); ImplVector v(otherVector);
v.m_i = this->m_j * otherVector.m_k - this->m_k * otherVector.m_j; v.m_i = this->m_j * otherVector.m_k - this->m_k * otherVector.m_j;
v.m_j = this->m_k * otherVector.m_i - this->m_i * otherVector.m_k; v.m_j = this->m_k * otherVector.m_i - this->m_i * otherVector.m_k;
v.m_k = this->m_i * otherVector.m_j - this->m_j * otherVector.m_i; v.m_k = this->m_i * otherVector.m_j - this->m_j * otherVector.m_i;
@@ -106,7 +106,7 @@ template <class ImplClass> ImplClass CVector3DBase<ImplClass>::crossProduct(cons
/* /*
* Cross product * Cross product
*/ */
template <class ImplClass> double CVector3DBase<ImplClass>::dotProduct(const ImplClass &otherVector) const template <class ImplVector> double CVector3DBase<ImplVector>::dotProduct(const ImplVector &otherVector) const
{ {
return this->m_i * otherVector.m_i + this->m_j * otherVector.m_j + this->m_k * otherVector.m_k; return this->m_i * otherVector.m_i + this->m_j * otherVector.m_j + this->m_k * otherVector.m_k;
} }
@@ -115,7 +115,7 @@ template <class ImplClass> double CVector3DBase<ImplClass>::dotProduct(const Imp
/* /*
* Multiply with matrix * Multiply with matrix
*/ */
template <class ImplClass> void CVector3DBase<ImplClass>::matrixMultiplication(const CMatrix3x3 &matrix) template <class ImplVector> void CVector3DBase<ImplVector>::matrixMultiplication(const CMatrix3x3 &matrix)
{ {
CMatrix3x1 m = matrix * (this->toMatrix3x1()); CMatrix3x1 m = matrix * (this->toMatrix3x1());
this->m_i = m(0, 0); this->m_i = m(0, 0);
@@ -126,7 +126,7 @@ template <class ImplClass> void CVector3DBase<ImplClass>::matrixMultiplication(c
/* /*
* Convert to matrix * Convert to matrix
*/ */
template <class ImplClass> CMatrix3x1 CVector3DBase<ImplClass>::toMatrix3x1() const template <class ImplVector> CMatrix3x1 CVector3DBase<ImplVector>::toMatrix3x1() const
{ {
return CMatrix3x1(this->m_i, this->m_j, this->m_k); return CMatrix3x1(this->m_i, this->m_j, this->m_k);
} }

View File

@@ -21,7 +21,7 @@ class CMatrix3x1; // forward declaration
/*! /*!
* \brief 3D vector base (x, y, z) * \brief 3D vector base (x, y, z)
*/ */
template <class ImplClass> class CVector3DBase : public CBaseStreamStringifier<ImplClass> template <class ImplVector> class CVector3DBase : public CBaseStreamStringifier<ImplVector>
{ {
protected: protected:
@@ -61,6 +61,16 @@ protected:
*/ */
virtual QString stringForConverter() const; virtual QString stringForConverter() const;
/*!
* \brief Clone as concrete implementation
* \return
*/
ImplVector clone() const
{
return static_cast<ImplVector const &>(*this);
}
public: public:
// getter and setters are implemented in the derived classes // getter and setters are implemented in the derived classes
@@ -90,7 +100,7 @@ public:
*/ */
bool isZeroEpsilon() const bool isZeroEpsilon() const
{ {
ImplClass v; ImplVector v;
v += (*this); v += (*this);
v.round(); v.round();
return v.isZero(); return v.isZero();
@@ -186,10 +196,9 @@ public:
* \param otherVector * \param otherVector
* \return * \return
*/ */
ImplClass operator +(const ImplClass &otherVector) const ImplVector operator +(const ImplVector &otherVector) const
{ {
ImplClass v; ImplVector v = this->clone();
v += (*this);
v += otherVector; v += otherVector;
return v; return v;
} }
@@ -212,10 +221,9 @@ public:
* \param otherVector * \param otherVector
* \return * \return
*/ */
ImplClass operator -(const ImplClass &otherVector) const ImplVector operator -(const ImplVector &otherVector) const
{ {
ImplClass v; ImplVector v = this->clone();
v += (*this);
v -= otherVector; v -= otherVector;
return v; return v;
} }
@@ -238,10 +246,9 @@ public:
* \param otherVector * \param otherVector
* \return * \return
*/ */
ImplClass operator *(const ImplClass &otherVector) const ImplVector operator *(const ImplVector &otherVector) const
{ {
ImplClass v; ImplVector v = this->clone();
v += (*this);
v *= otherVector; v *= otherVector;
return v; return v;
} }
@@ -264,10 +271,9 @@ public:
* \param factor * \param factor
* \return * \return
*/ */
ImplClass operator *(double factor) const ImplVector operator *(double factor) const
{ {
ImplClass v; ImplVector v = this->clone();
v += (*this);
v *= factor; v *= factor;
return v; return v;
} }
@@ -278,7 +284,7 @@ public:
* \param otherVector * \param otherVector
* \return * \return
*/ */
friend ImplClass operator *(double factor, const ImplClass &otherVector) friend ImplVector operator *(double factor, const ImplVector &otherVector)
{ {
return otherVector * factor; return otherVector * factor;
} }
@@ -301,10 +307,9 @@ public:
* \param divisor * \param divisor
* \return * \return
*/ */
ImplClass operator /(double divisor) const ImplVector operator /(double divisor) const
{ {
ImplClass v; ImplVector v = this->clone();
v += (*this);
v /= divisor; v /= divisor;
return v; return v;
} }
@@ -327,10 +332,9 @@ public:
* \param otherVector * \param otherVector
* \return * \return
*/ */
ImplClass operator /(const ImplClass &otherVector) const ImplVector operator /(const ImplVector &otherVector) const
{ {
ImplClass v; ImplVector v = this->clone();
v += (*this);
v /= otherVector; v /= otherVector;
return v; return v;
} }
@@ -340,14 +344,14 @@ public:
* \param otherVector * \param otherVector
* \return * \return
*/ */
double dotProduct(const ImplClass &otherVector) const; double dotProduct(const ImplVector &otherVector) const;
/*! /*!
* \brief Cross product * \brief Cross product
* \param otherVector * \param otherVector
* \return * \return
*/ */
ImplClass crossProduct(const ImplClass &otherVector) const; ImplVector crossProduct(const ImplVector &otherVector) const;
/*! /*!
* \brief Matrix * this vector * \brief Matrix * this vector
@@ -360,12 +364,9 @@ public:
* \brief Reciprocal value * \brief Reciprocal value
* \return * \return
*/ */
ImplClass reciprocalValues() const ImplVector reciprocalValues() const
{ {
ImplClass v; ImplVector v(1 / this->m_i, 1 / this->m_j, 1 / this->m_j);
v.m_i = (1 / this->m_i);
v.m_j = (1 / this->m_j);
v.m_k = (1 / this->m_j);
return v; return v;
} }
@@ -406,13 +407,13 @@ public:
* \brief Round this vector * \brief Round this vector
* \return * \return
*/ */
ImplClass &round() ImplVector &round()
{ {
const double epsilon = 1E-10; const double epsilon = 1E-10;
this->m_i = BlackMisc::Math::CMath::roundEpsilon(this->m_i, epsilon); this->m_i = BlackMisc::Math::CMath::roundEpsilon(this->m_i, epsilon);
this->m_j = BlackMisc::Math::CMath::roundEpsilon(this->m_j, epsilon); this->m_j = BlackMisc::Math::CMath::roundEpsilon(this->m_j, epsilon);
this->m_k = BlackMisc::Math::CMath::roundEpsilon(this->m_k, epsilon); this->m_k = BlackMisc::Math::CMath::roundEpsilon(this->m_k, epsilon);
return static_cast<ImplClass &>(*this); return static_cast<ImplVector &>(*this);
} }
}; };

View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2013 VATSIM Community /* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@@ -190,8 +190,7 @@ template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, P
*/ */
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator -(const PQ &otherQuantity) const template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator -(const PQ &otherQuantity) const
{ {
PQ minus; PQ minus = this->clone();
minus += (*this);
minus -= otherQuantity; minus -= otherQuantity;
return minus; return minus;
} }
@@ -210,8 +209,7 @@ template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, P
*/ */
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator *(double multiply) const template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator *(double multiply) const
{ {
PQ times; PQ times = this->clone();
times += (*this);
times *= multiply; times *= multiply;
return times; return times;
} }
@@ -230,8 +228,7 @@ template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, P
*/ */
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator /(double divide) const template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator /(double divide) const
{ {
PQ div; PQ div = this->clone();
div += (*this);
div /= divide; div /= divide;
return div; return div;
} }

View File

@@ -36,7 +36,7 @@ protected:
MU m_conversionSiUnit; //!< corresponding SI base unit MU m_conversionSiUnit; //!< corresponding SI base unit
/*! /*!
* \brief Constructor with int * \brief Constructor by integer
* \param baseValue * \param baseValue
* \param unit * \param unit
* \param siConversionUnit * \param siConversionUnit
@@ -60,6 +60,15 @@ protected:
return this->unitValueRoundedWithUnit(-1); return this->unitValueRoundedWithUnit(-1);
} }
/*!
* \brief Polymorphic clone as concrete class
* \return
*/
PQ clone() const
{
return static_cast<PQ const &>(*this);
}
/*! /*!
* \brief Init by integer * \brief Init by integer
* \param baseValue * \param baseValue
@@ -72,6 +81,7 @@ protected:
*/ */
void setUnitValue(double baseValue); void setUnitValue(double baseValue);
/*! /*!
* \brief Set the SI value * \brief Set the SI value
*/ */