Advertisement

GameObject class structure

Started by January 15, 2017 07:19 PM
1 comment, last by null; 7 years, 10 months ago

Hey all. I recently started doing some game development in C++ - I've been trying out both C++ and SFML.

Anyways, I've recently encountered this issue that I'm not sure how I'll overcome when the time comes. Well, it's not really an issue per se, but I'd like some clarification in any case.

In a language like Java, polymorphism is just a matter of changing a function in a derived class. I assume this is because pretty much everything is a pointer in Java.

However, in C++, I found out that an object has to be a pointer for me to properly implement polymorphism.

Is this actually the case, or is there some other method everybody uses that I'm unaware of?

However, in C++, I found out that an object has to be a pointer for me to properly implement polymorphism.


Sort of.

Pointers, references, or some other advanced programming techniques under the bucket of "type erasure" (that under the hood use pointers or references somewhere) can all provide dynamic polymorphism, like Java.

Value objects - which Java doesn't support for user-written classes - cannot be _dynamically_ polymorphic, but can be _statically_ polymorphic (a concept that mostly doesn't exist in Java). For instance, C++ functions and classes can be generated with templates, so you can write a single function that takes any type of value and operates on it.

Functions that operate on objects polymorphically can work on any kind of object in C++. e.g. you can get a reference or pointer to any object, no matter how it was created. The function doesn't and shouldn't care where the object came from.

That said, dynamic polymorphism is a bit rarer in C++ than Java, typically because polymorphism and class inheritance and such are _bad solutions_ for a number of problems. Java programmers tend not to notice how bad those solutions are because Java _forces_ people to use polymorphic objects for everything; C++ gives you a lot more options for when dynamic polymorphism is a suboptimal tool for the job.

Some examples:

// references should be preferred over pointers in most cases
void foo(base_type& ref) {
  ref.method(); // dynamically polymorphic
}

// higher level abstractions can also be polymorphic and are sometimes very preferable over base classes and inheritance
void foo(function<void(int)> func) {
  func(42); // "polymorphic" because func can be bound to a free function, member function, lambda, etc.
}

// templates are a form of static (compile-time) polymorphism
template <typename T>
void foo(T val) {
  val.method(); // tries to invoke T::method() on val, no matter what T is
}

In general, remember two things:

- you should _very rarely_ ever have a raw pointer in C++. If you're passing around ownership of an object, use std::unique_ptr or std::shared_ptr, and if you're just observing an object, use a reference or std::weak_ptr (and __strongly__ prefer unique_ptr and references as shared_ptr/weak_ptr can cause more problems than they solve if you're not careful!).
- don't use inheritance to solve every problem. that's Java-esque thinking that should be stamped out when moving to another language. :) inheritance solves a small few particular types of problem very well but leads to either inflexible code, overly-coupled code, or poorly-performining code when it's overused.

Sean Middleditch – Game Systems Engineer – Join my team!

Advertisement

However, in C++, I found out that an object has to be a pointer for me to properly implement polymorphism.


Sort of.

Pointers, references, or some other advanced programming techniques under the bucket of "type erasure" (that under the hood use pointers or references somewhere) can all provide dynamic polymorphism, like Java.

Value objects - which Java doesn't support for user-written classes - cannot be _dynamically_ polymorphic, but can be _statically_ polymorphic (a concept that mostly doesn't exist in Java). For instance, C++ functions and classes can be generated with templates, so you can write a single function that takes any type of value and operates on it.

Functions that operate on objects polymorphically can work on any kind of object in C++. e.g. you can get a reference or pointer to any object, no matter how it was created. The function doesn't and shouldn't care where the object came from.

That said, dynamic polymorphism is a bit rarer in C++ than Java, typically because polymorphism and class inheritance and such are _bad solutions_ for a number of problems. Java programmers tend not to notice how bad those solutions are because Java _forces_ people to use polymorphic objects for everything; C++ gives you a lot more options for when dynamic polymorphism is a suboptimal tool for the job.

Some examples:


// references should be preferred over pointers in most cases
void foo(base_type& ref) {
  ref.method(); // dynamically polymorphic
}

// higher level abstractions can also be polymorphic and are sometimes very preferable over base classes and inheritance
void foo(function<void(int)> func) {
  func(42); // "polymorphic" because func can be bound to a free function, member function, lambda, etc.
}

// templates are a form of static (compile-time) polymorphism
template <typename T>
void foo(T val) {
  val.method(); // tries to invoke T::method() on val, no matter what T is
}
In general, remember two things:

- you should _very rarely_ ever have a raw pointer in C++. If you're passing around ownership of an object, use std::unique_ptr or std::shared_ptr, and if you're just observing an object, use a reference or std::weak_ptr (and __strongly__ prefer unique_ptr and references as shared_ptr/weak_ptr can cause more problems than they solve if you're not careful!).
- don't use inheritance to solve every problem. that's Java-esque thinking that should be stamped out when moving to another language. :) inheritance solves a small few particular types of problem very well but leads to either inflexible code, overly-coupled code, or poorly-performining code when it's overused.

Wow, thanks! Yeah, I figured making everything I wanted to incorporate polymorphism with (which would be a lot of things in a game) a raw pointer would just get tiring after a while.

Yeah, I was worried about writing Java++ code. Thanks for the clarification!

This topic is closed to new replies.

Advertisement