nested classes and derivation

C

Christopher

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?

Is there a problem with Task1 being derived from BaseTask while its
nested Task1Stats is derived from TaskStats?

Did I get the syntax correct in my scenario example?
 
V

Victor Bazarov

Christopher said:
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?

Well, yes, but you do realise that an object of type 'Task1'
will have _two_ members 'm_stats', don't you? The one stored
in the base class subobject is going to be used when the base
class function is called that refers to it, and the derived
class 'm_stats' are going to be used by the derived class'
member funciton. Confusion up to wazoo.
Is there a problem with Task1 being derived from BaseTask while its
nested Task1Stats is derived from TaskStats?

Did I get the syntax correct in my scenario example?

You probably did. I am not sure it's the right design, though.

V
 
G

Grizlyk

Christopher said:
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 said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,743
Latest member
WoodrowMea

Latest Threads

Top