?
Solved

deriving classes

Posted on 2007-09-27
12
Medium Priority
?
299 Views
Last Modified: 2010-04-01
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
0
Comment
Question by:DJ_AM_Juicebox
  • 6
  • 3
  • 2
  • +1
12 Comments
 
LVL 8

Expert Comment

by:Anthony2000
ID: 19976148
Why do you need to have a derived class for your settings?
0
 

Author Comment

by:DJ_AM_Juicebox
ID: 19976157
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
 
LVL 8

Expert Comment

by:Anthony2000
ID: 19976168
In your derived MySettings, have you considered using simple functions to hide the details of the settings?  instead of referencing the vars directly.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 8

Expert Comment

by:Anthony2000
ID: 19976176
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
 
LVL 8

Expert Comment

by:Anthony2000
ID: 19976181
Then in your MyApp:

m_pSettings->strUsername();
0
 
LVL 86

Expert Comment

by:jkr
ID: 19976211
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
 
LVL 8

Expert Comment

by:Anthony2000
ID: 19976218
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
 

Author Comment

by:DJ_AM_Juicebox
ID: 19976282
@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
 
LVL 86

Expert Comment

by:jkr
ID: 19976331
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
 

Author Comment

by:DJ_AM_Juicebox
ID: 19976345
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
 
LVL 8

Expert Comment

by:Anthony2000
ID: 19978534
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
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 2000 total points
ID: 19978683
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

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Suggested Courses

864 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question