简体   繁体   中英

Design problems in C++

I have a raw buffer which contains number of different structs(which I couldn't modify) which I planned to wrapped inside a class like below so that I could invoke the virtual Process based on the concrete type.

class Base{
public:
  virtual void Process();
};

class DerivedA : public Base {
private:
 char* structBuf;

public:
  virtual void Process();
}

class DerivedB : public Base {
private:
 char* structBuf;
public:
  virtual void Process();
}

int main()
{
 for(int i = 0 ; i < 10; i++)
 {
  Base* a = FactoryObject();
  a->Process();
 }
}

My question is some of the objects depent on each other. For example, let say derivedA data would be processed first and derivedB needs the data from derivedA.

  • How or where could I store the derivedA object in main() so that I could utilize it in derivedB?

  • How could I know which objects from factory is derivedA so that I could store it?

Add a constructor to DerivedB that takes a DerivedA parameter. Construct your DerivedB instance only after you processed your DerivedA instance, passing to DerivedB the DerivedA instance.

Here comes dynamic_cast handy for you. If you have a Base* pointer, you try to do dynamic_cast. If it really is, then the result will be the DerivedA object. Else it is not DerivedA, returns NULL.

So in your main(),

    Base* a = FactoryObject();
    DerivedA *CheckObj= dynamic_cast<DerivedA*>(a);
    DerivedA *AObj = NULL;
    if(CheckObj)
    {
        AObj = CheckObj;
        AObj->Process();
    }
    else
    {
        if(AObj)
        {
            AObj->Process();
            CheckObj->Process();
        }
    }

I think I'm understanding your question.

In main you would have your object that holds the data you want passed around. Have a derivedA public data object (or you can make it private and set it with a set function) and make derivedA.data = main's data. Then when derivedA does its stuff, the object in main will still point to it. Then you repeat the process by handing the data to derivedB with derivedB.data = main's data.

If you make char* structBuf; protected instead of private then all derived classes can access it. As it stands I'm not sure how you'll implement the process function in your derived classes.

It sounds like you're looking for some cache or data-store of already processed information. You could write a class to store this type specific info and then retrieve it in later calls to your virtual process functions. Something like:

class DataCache {
  public:
  void store( DerivedA* data );
  void store( DerivedB* data );
  std::list<DerivedA*>& getDerivedA();
  std::list<DerivedB*>& getDerivedB();
}

Now your process function should take a reference to a DataCache object, so each call can store and get appropriately. DerivedB might implement process like:

DerivedB::process( DataCache& cache ) {
  std::list<DerivedA*>& a_data = cache.getDerivedA();
  //do something
  cache.store( this );
}

You could do something like this:

class DerivedA;

class Base{
public:
  virtual void Process();
protected:
  static std::vector<DerivedA*> dependencies;
};

class DerivedA : public Base {
private:
  char* structBuf;
public:
  DerivedA() {
    dependencies.push_back(this);
  }
  virtual void Process();
};

class DerivedB : public Base {
private:
  char* structBuf;
public:
  virtual void Process();
};

int main()
{
  std::vector<Base*> allBase;
  for(int i = 0 ; i < 10; i++) {
    allBase.push_back(FactoryObject());
  }

  for(int i = 0 ; i < 10; i++) {
    allBase[i]->Process();
  }

  return 0;
}

In short, while the objects are constructed the DerivedA ones are registering themselves in a static vector in Base, which means they are accessible in DerivedB once you are calling Process() on DerivedB types.

You must allow for all derived classes to be created before you can call Process. So, first map and create all and then map again and call Process(). This is of course not optimal since the base knows some about its inherited classes, but you insisted on having this factory pattern.

A better solution is to lift out the static vector from Base and store DerivedA elsewhere. But in the end it will boil down to you having to store DerivedA instances somewhere, and that registration should be done at construction, ie in the constructor of DerivedA. I dont know if a simple vector will do as registration, please modify this to suit your needs. For example you might want to look up DerivedA* with some identifier and need a hash or map instead.

I've interpreted your question as pertaining to reading in a file or stream which has a header section that sets out the subsequent instance definition sections.

#include <iostream>

class AbstractDataProcessor;

class ProcessorFactory
{
public:
    static AbstractDataProcessor* create(const char id);
};

class AbstractDataProcessor
{
public:
    AbstractDataProcessor() : next_(0) {}
    virtual ~AbstractDataProcessor()
    {
        if(next_ != 0)
        {
            delete next_;
            next_ = 0;
        }
    }

    void process(const char* buf, int size)
    {
        process(buf, 0, size);
    }

protected:
    virtual int do_process(const char* buf, int start, int size) = 0;

    void append(AbstractDataProcessor* chain)
    {
        if(next_ == 0)
        {
            next_ = chain;
        }
        else
        {
            next_->append(chain);
        }
    }

private:
    void process(const char* buf, int start, int size)
    {
        int next_start = do_process(buf, start, size);
        std::cout << "AbstractDataProcessor::process: start = " << start << " : size = " << size << " : next_start = " << next_start << std::endl;
        if(next_ == 0 || next_start >= size)
        {
            return;
        }
        next_->process(buf, next_start, size);
    }

    AbstractDataProcessor* next_;
};

class HeaderProcessor : public AbstractDataProcessor
{
protected:
    static const char header_sentinel = 'H';

    virtual int do_process(const char* buf, int start, int size)
    {
        int current = start;
        while(current < size && buf[current] != header_sentinel)
        {
            std::cout << "HeaderProcessor::do_process: buf[" << current << "] = " << buf[current] << std::endl;
            AbstractDataProcessor* section_processor = ProcessorFactory::create(buf[current]);
            if(section_processor != 0)
            {
                append(section_processor);
            }
            ++current;
        }
        return current + 1;
    }
};

class ElementProcessor : public AbstractDataProcessor
{
protected:
    int do_process(const char* buf, int start, int size)
    {
        foo_ = static_cast<float>(buf[start]);
        std::cout << "ElementProcessor::do_process: buf[" << start << "] = " << buf[start] << " : foo_ = " << foo_ << std::endl;
        return start + (sizeof(float) / sizeof(char));
    }

private:
    float foo_;
};

AbstractDataProcessor* ProcessorFactory::create(char id)
{
    std::cout << "ProcessorFactory::create: id = " << id << std::endl;
    switch(id)
    {
    case 'h':
        return new HeaderProcessor;
    case 'e':
        return new ElementProcessor;
    default:
        return 0;
    }
}

int main(int argc, char** argv)
{
    static const int buf_size = 6;
    char testbuf[buf_size] = { 'e', 'H', 'x', '3', 't', '[' };

    AbstractDataProcessor* testprocessor = ProcessorFactory::create('h');

    testprocessor->process(testbuf, buf_size);

    return 0;
}

its not the most elegant example, but it illustrates the idea of generating a linked list of processors that act on a single input stream of data. Each processor is capable of appending a new processor as appropriate, you could define another method "AbstractDataProcessor::insert" to allow for implementing a recursive delegation approach within each "do_process" method too. i haven't included any useful extraction methods, but it should be easy enough to walk the linked list and spit out pointers to something in main or wherever you need it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM