Re: nested classes and derivation
Christopher wrote:
This is going to be hard to explain. But I am looking for rules on
deriving nested classes in a scenario like the following:
class TaskLauncher
{
// launches tasks which are child threads
typedef std::vector<BaseTask *> Tasks;
Tasks m_tasks;
// desire to be able to dynamic cast BaseTask pointer
// to a concrete task type and be able to retreive
// its stats when stats can be differant types
};
class BaseTask
{
public:
...
private:
class TaskStats
{
public:
virtual const std::string GetStats() const;
...
private:
m_somestat;
}m_stats;
};
class Task1 : public BaseTask
{
public:
...
private:
class Task1Stats : public TaskStats
{
public:
virtual const std::string GetStats() const;
private:
m_somestat;
m_otherstat;
}m_stats;
};
I don't really nest classes very often, but I figured it would be
convienant when users of the class want a particualr kind of stats
that they can qualify it with the task type. i.e Task1::m_stats or
BaseTask::m_stats and get the proper type of stats.
Do the names of member variables get overidden properly? i.e does
Task1::m_stats contain a m_otherstats member?
Certainly, but not sure you have properly selected "private" access
modifier for Task1::m_stats and BaseTask::m_stats, to inherite
interface (access) you should use at least "protected", to use
external access you should use "public".
Of course, you need to declare for BaseTask at least one virtual
method (destructor, for example) to do dinamic_cast<>
Is there a problem with Task1 being derived
from BaseTask while its nested Task1Stats
is derived from TaskStats?
The problem is the fact that you are inheriting implementation. There
is often hard to maintain, share and upgrade the kind of inheritance
for a lot of classes.
For Task1Stats - do you really want two copies of m_somestat for
Task1Stats and Task1Stats with exact behaviour of TaskStats?
For Task1 - do you really want Task1 with exact behaviour of BaseTask?
Otherwise you can make abstract TaskStats and BaseTask classes and
inherite from them:
namespace Nabs{
//
class TaskStats
{
public:
virtual
const std::string
GetStats() const
=0;
virtual ~TaskStats(){}
};
//
class BaseTask
{
public:
virtual ~BaseTask(){}
};
//namespace Nabs
}
//
class BaseTask: public Nabs::BaseTask
{
protected:
class Implementation {...};
public:
class TaskStats: public Nabs::TaskStats
{
public:
const std::string
GetStats() const;
private:
Implementation
m_somestat;
}m_stats;
};
//
class Task1: public Nabs::BaseTask
{
protected:
class Implementation {...};
public:
class TaskStats: public Nabs::TaskStats
{
public:
const std::string
GetStats() const;
private:
Implementation
m_otherstat;
}m_stats;
};
If dynamic_cast<> will be used only to select proper m_stats, then
"virtual" access for m_stats is better - less expensive at runtime
than dynamic_cast<>. In the case you can make abstract BaseTask and
TaskStats
//prev TaskStats
namespace Nabs{
class TaskStats;}
//new BaseTask
namespace Nabs{
class BaseTask
{
public:
virtual
Nabs::TaskStats&
task_stat()
=0;
virtual
const Nabs::TaskStats&
task_stat()const
=0;
virtual ~BaseTask(){}
};}
namespace Ncct
{
//
template< class pImplementation >
class AbstractTask: public Nabs::BaseTask
{
protected:
class TaskStats: public Nabs::TaskStats
{
public:
const std::string
GetStats() const;
private:
pImplementation
m_somestat;
};
public:
//AbstractTask::TaskStats&
TaskStats&
task_stat()
{ return m_stats; }
//const AbstractTask::TaskStats&
const TaskStats&
task_stat()const
{ return m_stats; }
private:
//AbstractTask::TaskStats
TaskStats
m_stats;
};
// ***
//class BaseTask
//declare & define
class BaseImplementation {};
//define
template<>
const std::string
AbstractTask<BaseImplementation>::
TaskStats::
GetStats() const;
//or
//template<>class
//AbstractTask<BaseImplementation>::
// TaskStats;
//declare
typedef
AbstractTask<BaseImplementation>
BaseTask;
// ***
//class Task1
//declare & define
class Task1Implementation {};
//define
template<>
const std::string
AbstractTask<Task1Implementation>::
TaskStats::
GetStats() const;
//or
//template<>class
//AbstractTask<Task1Implementation>::
// TaskStats;
//declare
typedef
AbstractTask<Task1Implementation>
Task1;
//namespace Ncct
}
Ncct::BaseTask task;
Ncct::Task1 task1;
Nabs::BaseTask *ar[]={&task,&task1};
void foo()
{
ar[0]->task_stat().GetStats();
ar[1]->task_stat().GetStats();
}
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new