Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   OOP design question (http://www.programmingforums.org/showthread.php?t=13156)

rwm May 15th, 2007 6:28 AM

OOP design question
 
Hey!

I have a question about designing an OOP system:

Say we have a base class Base, and we derive a class Derived from Base. In the copy constructor, of Derived, one would have to call the methods that operate on the Base classes data, i.e

:

class Base {
        public:
                Base() {
                        a = 99;
                        b = 101;
                        c = 2232;
                }
                Base(const Base &src) {
                        a = src.a;
                        b = src.b;
                        c = src.c;
                }
                ~Base() {}
                int GetA() { return a; }
                void SetA(int _a) { a = _a; }
                int GetB() { return b; }
                void SetB(int _b) { b = _b; }
                int GetC() { return c; }
                void SetC(int _c) { c = _c; }
        private:
                int a;
                int b;
                int c;
};

class Derived : public Base {
        public:
                Derived() : Base() {
                        data = 34334;
                }
                Derived(const Derived &src) {
                        SetA(src.GetA());
                        SetB(src.SetB());
                        SetC(src.SetC());
                        data = src.data;
                }
                ~Derived() {}
                int GetData() { return data; }
                void SetData(int d) { data = d; }
        private:
                int data;
};


now my question is; is it ok to make the data of Base protected, so i can directly access them in the copy constructor? like this:

:

        Derived(const Derived &src) {
                a = src.a;
                b = src.b;
                c = src.c;
        }


i feel this is not a safe method? since any class taht derives from Base can access this data - when i want to keep it unaccessible...

is there an easier way to copy construct? or do I have to call Base's public methods to do this?

please help! thanks! :D

Seif May 15th, 2007 10:25 AM

well it kind of makes sense for derived classes to have access to ones base classes protected attributes. I would consider a review of what you have designed.

that said however, you could look into a friend class, it seems to be what you are looking for:

http://www.codersource.net/cpp_tutorial_friend.html

This will allow one class to have access to the private data of the class that declared it a friend.

rwm May 15th, 2007 10:40 AM

Hey Seif!

Thanks for the reply! Mmm well I suppose its ok... Just wondered what some would have to say about hte issue...

It seems better to use protected members than to declare the class as a friend. It breaks the whole OOP structure... I guess?

DaWei May 15th, 2007 11:10 AM

It really depends on what the classes are for and what you're actually trying to accomplish. Look at your getters and setters. They don't really protect your data. They allow the user to set any value that user wishes, but they only force him to do that in a roundabout way. That's obfuscation, not protection.

The purpose of a setter is to protect the data from being improperly set. You apparently have no rules to break, so there's nothing to protect. If, on the other hand, b should only be in the range 0-9, your setter can enforce that, whereas direct access cannot.

Once you've defined a useful setter, then you need a getter because you've shut the member down for direct access.

If you want to break that protection for any other class, then you have to know that unconstrained actions by that other class can't break your functionality. You're the designer. Only you know, unless you tell.

Relaxing that protection does not "break the OOP." Your object is still an object. It only breaks (possibly) the integrity of that object, functionally speaking.

Consider the accelerator on your car. It allows a specific range of inputs for fuel flow. Internal methods operate on that range to add a specific range of airflow to mix with it. That doesn't keep an unprotected member, say the butterfly valve, from being farbled with independently, thus modifying the intended behavor. Should you leave the butterfly valve out in the open, protect it somewhat with an aircleaner, or put the whole assembly in a welded-closed box? Your call.

rwm May 16th, 2007 4:14 AM

Hey DaWei!

Thanks for the explanation - that was very helpful! Of course, it all makes sense, the user can never access private or protected data, only public, so, in my case, the classes that the client will operate on can access/modify the Base class data, but not directly, only through the public member functions passed on through the hierarchy. So obviously its ok to make the data protected for all the derived classes - since it makes copy constructing much easier...

Thanks again! :D

Game_Ender May 26th, 2007 3:59 PM

I am really surprised no one gave the OP the answer he was actually looking for the "right" way to copy construct a derived class is to call the copy constructor of the super class like so:
:

  1. Derived(const Derived &src) :
  2.     Base(src)
  3. {
  4.     data = src.data;
  5. }

This allows you to keep all your data private as long you make the copy constructor public or protected.

grumpy May 26th, 2007 7:48 PM

Close, Game_Ender.

A preferable way would often be;
:

// Base constructor within class Base
Base(const Base &src) : a(src.a), b(src.b), c(src.c)
{
}


//  Derived constructor within class Derived
Derived(const Derived &src) : Base(src), data(src.data)
{
}

This is preferable if one assumes that (1) the members of both classes are either basic types OR have their own copy constructors that work as expected. AND (2) it is necessary to hand-roll the copy constructor for both class Base and Derived.

One additional rule of thumb is also that, if a class needs a hand-rolled copy constructor, it also needs a hand-rolled assignment operator.

In practice, if assumption (1) is true, then assumption (2) is rarely true. In the particular example, it is not actually necessary to hand-roll a copy constructor for either class Base or class Derived: the compiler generated versions work fine.

int is a basic type. So I would actually implement the classes in rwm's first example as;
:

class Base {
        public:
                Base() {
                        a = 99;
                        b = 101;
                        c = 2232;
                }

                // look Ma:  no hand-rolled copy constructor

                ~Base() {}
                int GetA() { return a; }
                void SetA(int _a) { a = _a; }
                int GetB() { return b; }
                void SetB(int _b) { b = _b; }
                int GetC() { return c; }
                void SetC(int _c) { c = _c; }
        private:
                int a;
                int b;
                int c;
};

class Derived : public Base {
        public:
                Derived() : Base() {
                        data = 34334;
                }

                // look Ma:  no hand-rolled copy constructor

                ~Derived() {}
                int GetData() { return data; }
                void SetData(int d) { data = d; }
        private:
                int data;
};


rwm May 28th, 2007 3:46 AM

hey guys I already know how to copy construct - sometimes i just miss stuff hwne i type out - im at work - always on the rush! but thanks for the replies - was intersting read!


All times are GMT -5. The time now is 2:15 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC