开发者

Inheritance in C++

EDIT 2:

Here is a simple summary of what I want to do (I think): I want to dynamically create global instances based on conditions that are calculated at run time.

You can skip to EDIT1 if you'd like to take a look at sample code, but at this point, the above bolded-text is probably the easiest to understand...

END EDIT 2.

My question is about polymorphism and inheritance. Specifically, I want to know if there is a way I could inherit functions and pointers from another class.

I have a class called Globals which contains various pointers to objects to other classes as well as various functions. Instead of copy/pasting code, I'll write up a simple example:

(I've removed header guards for simplicity and cleanliness)

The following is my globals.h and globals.cpp, respectively:

// Example of globals.h
#include <iostream>
#include <cstdio>
using namespace std;

class Globals {
  public:
    Globals ();
    virtual ~Globals ();

    void function1(char*);
    void function2();

    class Input *input;
    class Error *error;

};

// Example of globals.cpp
#include "globals.h"
Globals::Globals()
{
    input = new Input();
    error = new Error();
}

void Globals::function1(char*nm)
{
    cout << nm << endl;
}

Now, in my code for my Input class, say I want to use the function1(char*) method, would this be possible without passing an object to the Input class? What I mean by this is that I currently have my Input class being passed a *globals object, so then I could call the function like so: globals->function2();. But this can get very messy if I have a lot of functions within different classes. Additionally, is there a way I could use the Error pointer to object initialized in Globals? If Error had a function called error_func(), how could I be able to call it like so: error->error_func() from within my Input functions?

Thanks, and I apologize if I were too confusing in my question. I'll be happy to elaborate if needed.

Amit

EDIT 1: Added a simplified code to present what I want to do in a clearer way

// Example of globals.h
#include <iostream>
#include <cstdio>
#include "input.h"
#include "error.h"

using namespace std;


class Globals {
  public:
    Globals ();
    virtual ~Globals ();

    class Input *input;
    class Error *error;

};

// Example of globals.cpp
#include "globals.h"
Globals::Globals()
{
    input = new Input();
    error = new Error();
}

// Example of input.h
#include "globals.h"
class Input {
    public:
        Input();
        virtual ~Input();
}

// Example of input.cpp
#include "globals.h"
Input::Input()
{
    error->print("Hello\n"); // <-- THIS is really wh开发者_如何学编程at I want to accomplish (without being sent a globals object and say globals->error->print();
}

// Example of error.h
#include "globals.h"
class Error {
    public:
        Error() { }
        virtual ~Error() { } 
        void print(char*);
}

// Example of error.cpp
#include "globals.h"
Error::print(char* nm)
{
    cout << nm << endl;
}


If I'm understanding your question right, functions are automatically "inherited", at least for the purposes you need.

For example, your global class has two methods, function1(char*) and function2(). If you make a class:

class Descendent
    : public Global
{  };

int main()
{
    Global * global = new Global();
    Global * desc = new Descendant();
    char * str = "string";

    // These two will run the same function:
    global->function1(str);
    desc->function1(str);
}

To prevent that (functions being called based on the current type), you must use virtual, like:

class Global
{
    virtual void function1(char *);
};

class Descendant
{
    virtual void function1(char *);
};

int main()
{
    Global * global = new Global();
    Global * desc = new Descendant();
    char * str = "string";

    // These two will NOT run the same function:
    global->function1(str);
    desc->function1(str);
}

Now, I'm not entirely sure, but the singleton idiom may be of use here, depending on just how global your Global is. In that case, you would have a global like:

class Global
{
    static Global * GetSingleton()
    {
        if (!Global::m_Instance) Global::m_Instance = new Global();
        return Global::m_Instance;
    }

    void function1(char *);

    static Global * m_Instance;
};


class Descendant
{
    void function1(char *)
    {
        Global * global = Global::GetGetSingleton();
        // ...
    }
};

There are a variety of ways to work with globals and functions being needed between classes. One of these may be it, depending on what exactly you're doing. If not, I'll try to edit and suggest one that does work.


I'm imagining you have a situation like this:

struct A {
  void f();
};

struct B {
  void g();
};

struct C : virtual A, virtual B {
  C(A *ap, B *bp) 
    : A(ap), B(bp)  // This doesn't actually work -- theoretical
  {
  }

  void h() 
  { 
     f(); // calls A::f()
     g(); // calls B::g();
  }
};

Normally, when you create a C, you would be creating new As and Bs, but you would like to re-use existing ones instead, but still treat it like inheritance so that you don't have to explicitly specify which object to call.

Unfortunately, C++ doesn't support this. There are a couple of options:

You can make proxy classes that defer the function calls:

struct AProxy {
  AProxy(A *ap) : a(*ap) { }
  void f() { a.f(); }

  A &a;
};

struct BProxy {
  BProxy(B *bp) : b(*bp) { }
  void g() { b.g(); }

  B &b;
};

struct C : AProxy, BProxy {
  C(A *ap,B *bp) : AProxy(ap), BProxy(bp) { }

  void h()
  {
    f(); // calls AProxy::f() which calls a.f()
    g(); // calls BProxy::g() which calls b.g()
  }
};

This may help if you are using A's and B's in lots of different places.

If instead, you don't have many classes, but lots of calls to f() and g(), you might just do this:

struct C {
  C(A *ap,B *bp) : a(*ap), b(*bp) { }
  void f() { a.f(); }
  void g() { b.g(); }
  void h1() 
  {
    f();  // well at least the call is clean here
    g();
  }
  void h2()
  {
    f(); // and clean here
    g();
  }

  A &a;
  B &b;
};

If you don't have either of these cases, then just using the proper object each time like you were doing may be best.


Updated response:

Its sounds like what you want is actually the Factory pattern. I'm going to use logging as an example, where I assume that in one configuration you want to log and in another you might not want to:

// logger_interface.h
class LoggerInterface {
   public:
      virtual ~LoggerInterface() {}
      virtual void Log(const string& message) = 0;
   protected:
      LoggerInterface() {}
};

The first step is to create a pure virtual interface representing the behavior that is configurable as in the example above. We will then create a factory function that can construct one based on configuration:

// logger_factory.h
LoggerInterface* CreateLogger(LoggerOptions options);

When implementing the factory, we keep the different implementations hidden:

// logger_factory.cc
class DoNotLogLogger : public LoggerInterface {
   public:
      DoNotLogLogger() {}
      virtual ~DoNotLogLogger() {}
      virtual void Log(const string& message) {}
};

class LogToStdErrLogger : public LoggerInterface {
   public:
      LogToStdErrLogger() {}
      virtual ~LogToStdErrLogger() {}
      virtual void Log(const string& message) {
         std::cout << message << std::endl; 
       }
};

LoggerInterface* CreateLogger(LoggerOptions options) {
    if (options.IsLoggingEnabled() && options.ShouldLogToStdErr()) {
      return new LogToStdErrLogger;
    }
    return new DoNotLogLogger;
}

There is no reason why the object that you create dynamically in this way needs to be global; in fact, making it global is a really bad idea. Just create it where you need it, and pass it as a parameter to the functions that need it.

Original response:

Inheritance isn't the word you are looking for. Basically, what you are asking for is a static function:

class ClassName {
   public:
       static void methodName();
};

In the above, methodName can be invoked using ClassName::methodName() without requiring a specific instance of the class named ClassName. However, if you are to do this, it is more consistent with C++ style conventions to make it a freestanding function in a namespace like:

namespace name_of_namespace {
void functionName();
}

The above is invoked using name_of_namespace::functionName() as in the previous example, except with the benefit that it is easier to change or remove the prefix (e.g. via a using directive).

NOTE: from a design standpoint, you should only use a freestanding or static function if it does not rely on any state (other than the parameters passed to it) and there is no possibility of alternative implementations. As soon as there is state or alternative implementations, you really should pass around an object encapsulating this state, even if it is a pain to do, since passing around the object makes it easier to configure, makes it easier to mock-out in tests, and avoids threading issues.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜