3

This piece of code is a classical example of dynamic binding in Objective-C [1]:

float total = tareWeight;     // start with weight of empty container
int i, n = [self size];       // n = number of members
for (i = 0; i < n; ++i) {     // loop over each member
    id member = [self at:i];  // get next member
    total += [member weight]; // accumulate weight of contents
}
return total;                 // return total weight to caller

So, as a programmer with some experience in this language and doing my first steps in C++, I'd like to know: how would this be implemented in C++, given that it also supports some kind of late binding?

In this example, we assume that each member can be of any class, however implementing the weight method is a must, of course. These days mechanisms like protocols could be used as well, to enforce the implementation to be compatible (then declaring member as id<Matter>) but it's not needed at all to be able to work.

In C++, Would creating a super class with the so called virtual functions be the only alternative?

Edit

Just to clarify, the above code can be seen as a container class method which returns the total weight of its components. You don't know in advance what will be on the container, it can be any object. You only know that these objects respond to the message weight.


[1] Object-Oriented Programming, an Evolutionary Approach, 2nd Edition, 1991 - Brad J. Cox, Andrew J. Novobilski - Chapter 4 Page 65

sidyll
  • 57,726
  • 14
  • 108
  • 151
  • "Would creating a super class with the so called virtual functions be the only alternative?" Pretty much, yes. What's your problem with that? – leftaroundabout Mar 29 '12 at 14:38
  • 1
    What is "so called" about virtual functions? They are the definition of dynamic binding in c++ - the function to use is resolved at run-time. – tmpearce Mar 29 '12 at 14:41
  • 1
    @leftaroundabout there's a subtle difference: the Objective-C version uses an *implicit* interface - it works with any class that responds to a `weight` method with an integer return value, whereas the canonical C++ implementation requires the class to implement an *explicit* interface by subclassing a (possibly abstract) base and overriding its `virtual int weight()` member function. The latter requires the class to be modified unless it already happens to implement the interface. – pmdj Mar 29 '12 at 14:45
  • Ok, the implementation would use virtual functions. But what about declaring the `member` variable? I mean, how can I declare it as one class and initialize/use as another? Sorry, I know little about C++. – sidyll Mar 29 '12 at 14:48
  • 1
    @sidyll I'm hazy on what exactly you're asking, as I don't work in objective-c at all, but I think what you need to do is have `member` be a pointer-to-base-class (super class); when you call a virtual method on this pointer, the appropriate method is found. This must be implemented with pointers, if you use objects instead, you'll encounter "object slicing." I also want to point out that you can look into the "visitor pattern" for an alternative to implementing all functionality in the element classes themselves. – tmpearce Mar 29 '12 at 14:55
  • @tmpearce thanks for your comments. I edited the question to clarify a little. So, this is getting at the right point: it needs to be implemented with pointers. I have no idea on how to do that, and this is the question by the way, how this example would look like in C++. Note that in Objective-C you always work with pointers to objects, but I didn't even know this was possible in C++. – sidyll Mar 29 '12 at 16:13

2 Answers2

1

The closest you really get with C++ is a super class with virtual functions. Virtual functions if you really care about late binding, although in your example it isn't clear whether that is necessary. Weight could just be a publicly accessible data member in the super class.

The form of dynamic binding in C++ is strictly up and down the class hierarchy. This allows the compiler to do a certain level of checking rather than leaving it all to the run-time system. Unless you use unsafe casts.

Note that you do get multiple inheritance in C++, so the classes you want to be able to use only have to inherit from this superclass but can also inherit from anything else totally unrelated.

DRVic
  • 2,481
  • 1
  • 15
  • 22
  • 1
    Publicly accessible data member? Doesn't sound like a good idea, but it could be a public non-virtual function that accesses a data member. – leftaroundabout Mar 29 '12 at 14:50
  • 1
    That's partly a matter of taste: there are those who want all data members private, and require accessors for them. And there are those who see room for exceptions to that rule. – DRVic Mar 29 '12 at 15:14
  • Thanks @DRVic. I slightly edited the question. And good point about the multiple inheritance, which comes useful in these cases. – sidyll Mar 29 '12 at 16:15
1

You member variable would need to be a pointer to the weighable base class. Such a pointer can refer to any derived instance.

Since pointers bring about memory leak risk, it's clever to make it a smart pointer. C++11 has unique_ptr. So you class could look like

class heavyContainer {
  std::vector<std::unique_ptr<weighable>> members;
 public:
  float total_weight() {
    float result = tareWeight;
    for(auto& member: members)
      result += member->weight();
    return result;
  }
  ...
};

To initialize members with arbitrary derived instances of weighable, you need to heap-allocate these objects. That can be a bit tricky since there is no general way to copy objects referred to by a base class pointer. One way is to make the insertion function a template:

template<class WeighableDerivedObject>
heavyContainer::insert(const WeighableDerivedObject& obj){
  members.push_back(new WeighableDerivedObject(obj));
}

This could be made a bit more efficient with C++11 move semantics.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • Thanks, that clarifies a lot, and I see I have a lot to study too — some of this syntax still difficult for me. The loop can be made easier with fast enumeration in Objective-C too, but I just wanted to keep the original example from the book (which dates from before these loop facilities in the language). In my defense under the language war :-) Brad Cox even says in his book that the only substantial difference between a OOP and conventional programming is the message selection mechanist. And this, while present in C++ (kind of), is too much obscured and carries other complications. – sidyll Mar 29 '12 at 16:27