1

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 what 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;
}
9
  • Please suppose I have Input and Error classes, and those are properly/appropriately #included Commented Sep 22, 2011 at 2:25
  • Rather than trying to describe your code, please just post the code. Commented Sep 22, 2011 at 2:27
  • @OliCharlesworth: The code as it currently stands is rather lengthy. I could write up a small (simplified) version of what I am trying to do and post that. Would that be helpful? Commented Sep 22, 2011 at 2:28
  • 1
    Simple is good. I have a question as to the overall purpose: is Globals supposed to replace real globals because globals are bad? If not that, what is the purpose of Globals? Commented Sep 22, 2011 at 2:34
  • @outis: I hope the edit clarified that a bit Commented Sep 22, 2011 at 2:42

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Yep. The bit on functions and virtual won't help you terribly much, but your global class could very easily be a singleton. That would allow you to initialize the input and error objects and then use the same ones later. Some people don't like singletons, but as with most other designs, it should be used with care but does solve a problem (very much like the one you have now).
Oh man, that Singleton notation is rather confusing to me (sadly I'm not at all experienced in C++). There's no easy way to inherit functions and instances from one class to another?
Thanks for your input thus far, you've certainly helped. Would you mind looking at my second edit to see if there's possibly an easy way of dynamically creating global instances ?
Singletons are actually rather simple, they rely on the static modifier. A quick Google search will get you some decent info, even the wikipedia article is rather informative. To calculate them at runtime, you can do that in the singleton (where I have it create a new Global), but you'll have to be careful what conditions you rely on. Recreating them at runtime depending on conditions can also be done, but you'll probably end up with a mess.
1

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.

3 Comments

I've posted an edit that describes what I like to do. I basically want to inherit an object instance that was created / defined in a global class
I'm using A,B, and C here to make the answer more concise, but I was thinking class A and B were similar to your Globals and Error classes, and C was similar to Input.
I was thinking that the main thing you were trying to avoid was having to use specific objects for each call. This answer demonstrates ways to reduce those.
1

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.

4 Comments

Ahhh, I think you're most definitely on to something. When I looked through examples of what I want to do, I definitely saw namespace declarations!
Would I be able to carry on instances declared in Globals though? That would really be ideal, since it keeps things cleaner. I've made a recent edit that (I think?) shows what I want to do in a clearer way than was previously presented
@Amit, while technically you could mark the pointers, themselves, as static, this is really bad practice; it will make your life hell when you try to make your program multithreaded or when attempting to mock out the global data in tests. Instead, just create an instance of your interface and pass it around as needed.
Yeah this seems to be pretty hellish. I'll stick to the basics, even if it means to pass around many instances to certain functions. Oh well. Thanks a lot for your input. I think both your answer and @peachykeen are probably correct. I gave you both +1's, but I think I'll give peachykeen the check. It's always difficult to decide who gets the check at the end. Again, thanks a lot for your help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.