Right, yeah. Transform is just a component.
Transform is a component, and an instance of the component is part of the GameObject base class. Any GameObject comes with a Transform component pre-installed.
I'm going off-topic to nitpick, sorry
I agree with you.
As you wrote, they are well understood and despite their problems they mostly work okay.
As you mention, in principle you can implement the functionality of a game object in other ways, such as providing your own function pointers for whatever functionality you want. That would offer several benefits. That is more common with plugin architectures, or in languages like JavaScript or Python or Perl, where it doesn't matter what the things are called, all that matters is that you have something that looks right and matches all the slots and tabs as parameters or data, or that can be queried to give things that match the requirements. But since "easy" and "familiar" often win over "pure", the solutions the big engines offer really avoid the biggest problem.
On the virtual function pattern, that's a fun one. In some ways it is like a sharp knife, the young'ins always end up getting cut a few times until they figure out how to avoid the sharp parts.
Virtual functions are an amazing solution when the problem is that you need to vary behavior based on the concrete type. That is, if you are calling and doing different functionality for each thing it is extremely difficult to beat . Unfortunately they are a terrible solution when that behavior is no functionality. The "do nothing" virtual function is a cost that accomplishes nothing. Good code bases address this. Poor code bases make everything virtual, or in Java, never make anything final.
Since we're in the lounge and we can ramble, those of us with years of experience know quite well just how much those virtual functions can harm performance. Calling thousands of virtual functions every frame that do nothing is a terrible waste. They have a cost to look up the proper function, then the cost of a call, then the cost of returning. It may only be ten or twenty nanoseconds per call, but multiplied by many thousands you can easily reach microseconds of wasted time.
There are a few good and common improvements. Unity uses one common pattern and Unreal picked another.
Unreal chose the pattern to have a flag in the base class that tests if the function should be called, then the cost is only paid if the flag is set. Since it is in the base the variable is inlined and looks at the data bundle that is probably already on the cache with the object. That improves the time to a fraction of a nanosecond if the call doesn't exist, plus the full cost if it does. However, it still has the cost of doing all those tests.
Unity uses the pattern to scan early (at load time) to see if the functions exist, then only call the functions where it exists by registering them and going through the registered items. It gets the improvement that unimplemented functions aren't called. The drawback is that if implemented it is always called, an active object cannot de-register for updates. So it avoids the problem of the additional tests like Unreal's model (yay!) but cannot readily be removed from the list if there is nothing to do (boo!).
The best systems I'm aware of for those are for the things that need it to register that they need to be called, and are removed when they can be stopped. The collections of functions can all be called as tasks. started in parallel if the system is up for that. All the functions are indirect calls rather than virtual dispatch, and there is no cost to test the status. Items can be removed when they're done, added back on if that becomes necessary. You only pay the cost for work you actually need done, and everybody is a winner.
But sadly, those systems have some added complexity and are slightly more difficult to use correctly, so we're back to the earlier "easier" patterns of using comfortable, familiar names, along with their associated costs.