I’m a university student learning programming. For practice I’m writing a blackjack program. I’m using C++ and doing an object oriented approach to this.
I have a Deck class designed that basically builds and shuffles a deck of cards. The deck generated is composed of an array of 52 Card class objects. That’s what I have so far.
My plan is to have a Dealer object, which has a Deck of 52 Cards deal a Card to a second Player object and then deal to the Dealer’s own hand.
My first question is: Is it bad practice to make the array of Card objects public in the Deck class?
I ask this because I consider the array an attribute and was taught that most attributes should be made private. I don’t want to start using bad or lazy practices in my projects and want to do it the right way.
Another question: How are objects, such as the Card object used in my blackjack program, generally moved from within an object -like the dealer- to a second object like a player?
Yes. In general, data members should always be private. It is good OOP to create an interface with no associated data that defines what operations can be performed on the object, and then to provide a concrete class that implements that interface. The data is an implementation detail that should not be visible in the interface or even in the fully concrete class. As an example of why it is bad, you might implement your class using an array of Card objects right now, but maybe later you decide to use a bitset where a single bit indicates whether the card is or isn’t present in the deck. If you make your Card array object public, changing the representation in that manner would break other users of your class; however, if you keep it private, you can make that change without impacting the users of your class.
It depends on whether the other object needs to access the original card object, whether the other object will hold onto the original object for a long time or only a short time, or if the other object is able to handle only a copy of the card. It also depends on whether the card is a concrete class or a polymorphic type, since polymorphic objects can only be passed by pointer or reference (because passing polymorphic objects by value will lead to code slicing). With concrete objects, you have the option to pass a copy unless you need to modify or access the original object, in which case a reference is needed. Choosing the right way to pass objects is somewhat complicated, but hopefully this will clarify:
Pass by value if:
It is a primitive type or small, non-polymorphic concrete type that does not need to be modified.
Pass by constant reference — that is
const T&for some typeT— if:is non-polymorphic and cheap to copy, so you can create a copy if you need to hang onto
it.
Pass by reference — that is
T&for some typeT— if:is non-polymorphic and cheap to copy, so you can create a copy if you need to hang onto
it.
Pass by constant smart pointer to a const — that is
const shared_ptr<const T>&for some typeT— if:Pass by constant smart pointer — that is
const shared_ptr<T>&for some typeT— if:I have given each of the above in deliberate order; you should try the first one that will suffice for the job, only moving onto the next if the previous is not sufficient. Also, I should add that boost::call_traits<T>::param_type can help you choose between passing by value and passing by constant reference in the case of concrete non-polymorphic types (it can determine, based on the size of the object, whether pass by value or pass by constant reference is better).