简体   繁体   中英

C++ class best practice

I'd like to know some best practice when designing c++ classes.

To put it in context, I have a c++ class named Vec3.

class Vec3{
private:
    float elements[3];
public:
    Vec3(Vec3 v1){...}
    Vec3(int x, int y, int z){...}
    Vec3 add(Vec3 v1){...}
    Vec3 add(int x, int y, int z){...}
    ...
    Vec3 multiply(Vec3 v1){...}
    ...
    int dotProduct(Vec3 v1){...}
    Vec3 normalize(){...}
    ....
    int operator[](int pos){...}
};

So, I have this class that does computing over a Vector of size 3. I'd like to know what's better. Working with pointers or not.

Should I return pointer and have my parameters as Pointers or not.

Vec3 add(Vec3 v1) or Vec3* add(Vec3 v1) or Vec3* add(Vec3* v1) or....

Now I'm confused, I don't know if I should use pointer or not in my class. I guess there is always a way to send my arguments to function that don't handle pointers...

Vec3* v2 = new Vec3(1,1,1);
Vec3 sum = v1.add(*v2);

And there is a solution that is probably the best of all I can come up with.. having both functions

Vec3 add(Vec3 v2){...}
Vec3* add(Vec3* v2){...}

But I fear this will lead to duplicate code and may be overhead.

Thank you for answers...btw, I could use a template to change the size of the Vector but I prefer to keep my Vec3 class alone and create a Vec4 class or name it Quaternion.

EDIT Here is the solution I came with. Feel free to comment or modify or reuse the code. One thing. I just want to mention that, in my case, This class is supposed to be transparent. Just like we add numbers.

int i = 10;
int j = 15;
int k = i + k;

If the add overload modify the object that is calling the function in this case i. I would endup with ak being a reference to i and i being equal to 25. But what we really want here is ak equal to 25 and i,k unchanged.

Thats how my class work. Vec3 k = i + k will not modify i or k because we are creating a new number from these values. The only case where I return a reference is for +=, -=, ++, --..., set([XYZ])? and normalize.

It could be fun to do something like myvec.setX(10).normalize().scale(10)

NOTE: scale should return a reference. I didn't see it but I guess it should be better this way.

Vec3 t = myvec.normalize().scale(100).copy();

http://pastebin.com/f413b7ffb

Thank you all, I'll be working on the Matrix class now.

These are the rules I usually stick to. Note 'usually', sometimes there are reasons for doing things differently...

For parameters I don't intend to modify I pass by value if they aren't too large since they will be copied. If they are a bit large or aren't copyable, you could use a const reference or a pointer (I prefer const reference).

For parameters I do intend to modify, I use a reference.

For return values I will return a copy whenever possible. Some times it's handy to return a reference (this works well for a single function for get/set where you don't need to do any special processing when the item is fetched or set).

Where pointers really shine in my opinion is for instance variables where I want control over when it is constructed or destructed.

Hope that helps.

Since the int's are primtives, leave them as is. for anything with vec3's use references.

eg.

Vec3 add(const Vec3 &v1){...}

In C you'd use a pointer, but in c++ a reference is usually better for objects.

Vectors have known semantics (known for you and the users of your class), so I would consider overloading the operators (+, -, +=, -=) in doing so, I would use the regular definitions rather than changing them:

// instead of add:
class Vec3 {
public:
   Vec3& operator+=( Vec3 const & rhs );
};
// implemented as free function:
Vec3 operator+( Vec3 const &lhs, Vec3 const & rhs);

I would avoid using pointers. References are more natural, and there is only a very small set of situations were you do need them instead of references / values. Avoid duplicating your functions (with/without pointers) as that will make your code more complex unnecessarily, as you already posted in the question, you can always dereference a pointer to retrieve a reference.

Offer both a constant and a non-constant operator[]:

class Vec3 {
public:
   float operator[]( size_t pos ) const; // returns copy, data does not change
   float& operator[]( size_t pos );  // returns a reference and allows changing the contents
};

EDIT: I forgot to mention about the size_t detail: Prefer using unsigned / size_t for index parameters instead of signed integers.

If you implement operators like operator+=() and operator*=() , you'll want it to return *this as Vec3& .

Vec3& operator+=(const Vec3& v2) {
    // add op
    return *this;
}

For other basic operators like operator+() and your add() you will want to return a copy :

Vec3 operator+(const Vec3& v2) {
    Vec3 ret;
    // add
    return ret;
}

You almost certainly don't want the parameters be pointers in that case. Consider this example for why:

// Error: not possible to take the address of the temporary
//        return value. 
v2.add(&someFunctionReturningVec3());

For references to constant that is no problem. You could easily nest operations even:

// declaration: Vec3 add(Vec3 const& v);
v2.add(v1.add(v3));

There is no need for having the arguments as pointers in this case, and you really shouldn't return a new object for all operators like that.
In OO programming, the idea is to operate on the actual object, eg having


void add(Vec3 v1);
void multiply(Vec3 v1);

I would also say that you should stick to taking Vec3 objects as arguments (and not x,y,z). If you only have x,y,z, you can call add(Vec3(x,y,z)).

This page contains a really good discussion on this subject: http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html

As greyfade mentioned, you should be concerned about copy semantics. In this case, you should add these methods as well:

class Vec3 {
public:
  Vec3(const Vec3& rhs) {
    copy(rhs);
  }

  Vec3 operator=(const Vec3& rhs) {
    copy(rhs);
    return *this;
  }

private:
  void copy(const Vec3& rhs) {
    // copy state from rhs
  }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM