deriving classes

Hi,

I made some base classes that work with eachother like:

class BaseSettings {
     string m_strStartPath;
};
class AppBase {
     BaseSettings* m_pSettings;
     void DoSomething() { cout << m_pSettings->m_strStartPath; }
};

now I derived from both, and want to use my specialized classes, so I have something like:

class MySettings : public BaseSettings {
    string m_strUsername;
};
class MyApp : public BaseApp {
    MyApp()
    {
        m_pSettings = new MySettings();
    }
};

that's fine, but now when I want to use the additional member 'm_strUsername' of the settings object allocated in the derived app class, I've lost access to it. I could always keep doing:

    reinterpret_cast<MySettings*>(m_pSettings)->m_strUsername;

but that will most likely be a nightmare having to put that all over the place. I could also just make one new member of MyApp like:

    MySettings* m_pMySettings;
    MyApp()
    {
        m_pSettings = new MySettings();
        m_pMySettings = reinterpret_cast<MySettings*>(m_pSettings);
    }

but that seems awkward too, then i have two instances of the settings pointer seemingly.

What would you recommend?

Thanks
DJ_AM_JuiceboxAsked:
Who is Participating?
 
itsmeandnobodyelseConnect With a Mentor Commented:
Some remarks on the design:

>>>> reinterpret_cast<MySettings*>(
Actually a reinterpret_cast is wrong. You would need a dynamic_cast which casts between a baseclass and a derived class (pointer or reference). An old C cast would do the same. A reinterpret_cast is used if you still want to use the same bits but with a variable of a different type, e. g. if you want to use pointer as an integer address:

      AnyTypeOrClass* ptr;
      unsigned int address = reinterpret_cast<unsigned int> ptr;

You may argue that the reinterpret_cast worked. Yes, that is because with single-inheritance all classes share the same pointer, so that the reinterpret_cast not really harms. But actually that isn't a must. Future compilers may do it differently. And with multiple-inheritance there are different pointers involved.

>>>> MyApp()    {
>>>> m_pSettings = new MySettings();

You may consider whether that statement really is senseful. Or, better, whether it is senseful to have a BaseSettings pointer as a member in the AppBase. Using baseclass member pointers shouldn't be done if there is no benefit. Here you could have a MySettings* m_pSettings member in MyApp and remove the member in BaseApp and all is good. Things were different if you could use some functionality in AppBase and have a m_pSettings for the other app class as well. If so, then you can consider how to make virtual functions so that the AppBase could handle it BaseSettings pointer to virtually do different things. In neither case I see the necessity for a cast.

Note, when calling a virtual function, control goes to the derived object and the this of this object never needs to be casted. That means with the first virtual call you always have successfully avoided casting. So, if you let the derived object do what it is supposed to do rather than do something with the derived object using a baseclass pointer, you are always fine. And the whole thing is called OO.

Regards, Alex


0
 
Anthony2000Commented:
Why do you need to have a derived class for your settings?
0
 
DJ_AM_JuiceboxAuthor Commented:
because i have two applications with virtually the same settings, so they share a common base class. Then there are two derived instances which allow them to extend with their differences.

These classes automatically generate sql tables reflecting their fields and sql statements for their fields, which is why they all use this derivation scheme from a common DatabaseTable field.
0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

 
Anthony2000Commented:
In your derived MySettings, have you considered using simple functions to hide the details of the settings?  instead of referencing the vars directly.
0
 
Anthony2000Commented:
This would hide some of the details as to who really has which settings in which class. And MySetting and the BaseSettings would know how to retrieve and save those settings.
0
 
Anthony2000Commented:
Then in your MyApp:

m_pSettings->strUsername();
0
 
jkrCommented:
As always, I'd suggest to use pure virtual interfaces for that purpose, e.g.

class IBaseSettings {
enum SettingType{ Base, Mine}
     virtual SettingType GetType() const = 0;
     virtual string GetStartPath() const = 0;
};
class AppBase {
     IBaseSettings* m_pSettings;
     void DoSomething() { cout << m_pSettings->GetStartPath(); }
};

class IMySettings : public IBaseSettings {
     virtual string GetUserName() const = 0;
     virtual SettingType GetType() const { return Mine;}
class MyApp : public BaseApp {
    MyApp()
    {
        m_pSettings = new MySettings();
    }
};

That way, you have an exact control about what interface implementation you are dealing with and can cast and use it accordingly.

0
 
Anthony2000Commented:
and of course:

you would refer to m_strStartPath;

m_pSettings->strStartPath();

One minor downside is that the new derived class MySettings would need to contain functions to access all of its settings as well as its base class settings.

0
 
DJ_AM_JuiceboxAuthor Commented:
@jkr:

how would you use that though in the derived app class - I mean you still have to cast at some point:

    MyApp()
    {
        m_pSettings = new MySettings();
        // now m_pSettings thinks it's still the base class type.
        // so what do I do if I want to print GetUserName() :
        switch (m_pSettings->GetType()) {
              case Mine:
                   ((IMySettings*)m_pSettings)->GetUsername();
                   break;
         }
    }

sorry for the confusion
    }
0
 
jkrCommented:
Yes, casting is required at that point. If you need that without casting you moght want to consider a setup like

class ISettings {

 virtual bool GetValue(const string& value_name, string& result) {
   
    // if name is 'StartPath', fill in path, if 'UserName' the name, return FALSE if nothing
  }
}
0
 
DJ_AM_JuiceboxAuthor Commented:
Ok what I think I'll do is declare those functions pure virtual like:

class AppBase {
    virtual string GetStartupPath() = 0;
    virtual int GetStartCount() = 0;
};

and it will be the responsibility of derived classes to make sure they hook it up however they want. Is that ok you think?

Thanks
0
 
Anthony2000Commented:
jkr,

Does this mean that the method I propose is not a simple solution?
DJ_AM_Juicebox's app appears to only have one instance of the settings class. So I am having trouble understanding why the virtual base class. Forgive me asking a question, but this may benefit DJ_AM_Juicebox as well.

Thanks,

Anthony
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.