How to properly design objects

One thing I really struggle with is OOP. I don't know why it just doesn't click. I can program "Top down" all day without fault, but when trying to separate out objects into their own little code that can work independantly from the rest I struggle exponentially. Getting that code to run cyclically is another life time away for me.


Something I like and am kind of good at is Electronics. I've done plenty of projects, kits, microcontroller, radio experiments etc I thought it would be a good place to start for me doing OOP and making a little "Electronics sim". I did something similar a while back, but it was only connected logic gates, which would give the final result at the end depending on how the gates were connected. Nothing like what I want to accomplish, a real cycle based circuit.

I can't even seem to get off the mark here, and I'm trying to start off with the simple stuff Wires and Connectors... Can someone take a look at this? Am I walking backwards?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <vector>

// Low level data, 5V high, 0v low, 1's & 0's
class Dataline
{
private:
	bool is_high; // Is data present
public:
	Dataline(bool d = 0) { is_high = d; }
	~Dataline() {}
	void Write(bool d) { is_high = d; }
	bool Read() { return is_high; }
};

// Connector, a series of a data lines grouped together, PATA, SATA, MOLEX, SPI ETC
class Connector
{
private:
	bool male_female; // Does it plug into something, or does something plug into it
	std::vector<Dataline*> data_bus; // HELP: Dataline is pointer? Connector doesn't have data lines of it's own?
public:
	Connector(std::vector<Dataline>& dl) {} // Give the connector access to the datalines
	~Connector() {}
}

// Two connectors, connected and conversing data through data lines
// Should be arbitrary number of connectors but one step at a time
class Connection
{
private:
	Connector* m_connector;
	Connector* f_connector;
	bool state; // 0: M->F | 1: M<-F - Who is Tx, who is Rx
public:
	Connection(Connector* A, Connector* B) {}
	void Do()
	{
		if(!state)
		{
			// Female connector transmitting data
			// Male connector is receiving
		}
		else
		{
			// ...
		}
	}
}


It seems so... excessive. When I do electronics personally I don't struggle to work out where data is being received and transmitted I know it implicitly. Trying to map this out in the programming world has got me really doubting my own ability.
Last edited on
Your classes make sense and are easy to follow. Your variable names are mostly clear. You have good comments.

I'm not sure what you're trying to accomplish. If you're writing a CAD program or trying to simulate an electronics package of some sort, this level of detail is probably appropriate.

I do have some minor comments on your code though.
Lines 12-13: Read and Write usually refer to file I/O. Traditionally, getters and setters would be names like get_high() and set_high (bool newval).

Line 20: male_female is ambiguous. Can't tell from the name whether true is male or female. Would suggest calling it is_male. Then the type of the connector is clear.

Line 21: I would inclined to make it a vector<Dataline> rather than a vector of pointers. However, this decision depends on whether the Dataline objects that make up the vector are changing during the lifetime of the connector.

Line 23: You don't set data_bus to dl.

Lines 32-33: Same arguments here as with data_bus. If the Connector objects are static, I would use copies of the objects rather than pointers. If the Connector objects are changing dynamically, then pointers are appropriate. The caution with pointers is the lifetime of the Connectors. If what they point to goes away, then your pointers are of course no longer valid.

Line 34: Can the connection be tri-state? If so, I would use an enum here. i.e. Tx, Rx, or idle? If it is truly binary, then I would name it is_mf to make the sense of true clear.


Line 36: You don't set you member variables to A and B.

Your decision to use pointers over real objects depends on your idea of object ownership*. If you're imagining modeling cycles with this, the ownership question becomes... confusing; you'll end up having to break the cycle somewhere, and doing that is tricky.

My observation is that your objects don't inherently own one another. They depend on each other to form a circuit, but a connector doesn't control its connections and a connection doesn't control it's connectors.

The dependencies between your objects form a directed graph. In a real circuit, the edges would be connections and the nodes components. I would suggest that you model that graph directly (maybe with the Boost Graph Library) and handle the interactions between them without trying to hide the graph structure inside your objects.

*Smart pointers (shared_ptr, unique_ptr, weak_ptr) both enforce those ownership semantics and make them explicit; as a side effect, they also will manage memory for you --- if you use pointers at all, consider those.
Last edited on
Topic archived. No new replies allowed.