I'm working on Finite Element code in MATLAB, and the number of constants (for instance user input defining the geometry, physics, numerical solution scheme) is substantial.
You probably just named the three objects where these constants should reside.
Currently, I've been passing variables between subroutines using global statements,
Yeah, stop doing that.
but these offer no indication what the variables are or what their use is; not ideal as the code expands.
It's not ideal with tiny bits of code.
I want to encapsulate related constants in MATLAB objects (for instance GEOMETRY, for all the geometry constants, etc. In this usage case, they will essentially be structs; they will have no associated private functions
And here's your problem. Why not? This is not object oriented. If you don't put the methods that need the constants here, you're turning the object inside out. Spreading knowledge around makes your code ridgid. Hide what your other objects don't need to know from them. Don't force me to ask
Geometry for things I need from it. Let me tell
Geometry what to do. See, tell, don't ask1,2.
I want to encapsulate related constants in MATLAB objects (for instance GEOMETRY, for all the geometry constants, etc. In this usage case, they will essentially be structs; they will have no associated private functions.) Is this bad coding practice? It seems to run contrary to everything I know about good object-oriented programming.
Encapsulation done right is more than clustering. I can see your constants from outside. That means I know about them. That means I'll end up depending on them. That means you can't change them, rename them, or move them without breaking me. Use data hiding and you can do as you like with them and I'll never know.
Eventually (once I'm done prototyping), I want to convert everything to C++, so my main concern is doing this in a way that is acceptable in both programming paradigms.
A language is not a paradigm. Your paradigm is, ostensibly, object oriented. You can do that in languages not even designed for it. You just have to follow it's practices.
If jumping from language to language turns converting into your main concern maybe just use one language. Your main concern should be the problem you're trying to solve. Anything that distracts you from that had better be doing something amazing for you.
whereas C++ would require definition of a class
Classes are not required to write object oriented code.
Am I "breaking the rules" using objects as I've proposed? If so, is there a better way to structure my data?
You're breaking a very important one. Spreading knowledge around hurts flexibility. I'd rather see you define pi in multiple places then do this. If the constant is something you want to adjust in one place then make that one place a full rights citizen and group methods around it.
But if you insist on providing access to things that don't need it, at least make the places you put the public constants easy to find. I find
Math just fine. But that's a library. People maintaining your software will have many other things to think about. Don't ask them to memorize a complicated structure to find the constants they're looking for. Avoid names like
Misc. Make the structure and names meaningful.