0

I have a class named Complex with many member methods returning objects of that Complex class, and many member methods taking objects of class Complex as parameter.

class Complex
{
public:
    Complex sampleFunc(Complex c) { ... }
    Complex operator+(Complex c) { ... }
};

This would be a library, so other users would be using my class. Since, most users use:

Complex *ptrObj = new Complex();    // declaration 1

rather than using:

Complex obj;                        // declaration 2

The code I have written above would work with declaration 2 but not with declaration 1. I can change the prototype for sampleFunc() as follows:

Complex* sampleFunc(Complex *c) { ... }

But then I cannot meaningfully change the operator+() function to get the effect of adding two objects (rather than erroneously adding two pointers). So, what API should I be exposing - that works with declaration 1 or that works with declaration 2 or should I provide two versions for each function? I believe that passing pointers to functions would work faster, but then operator overloading would be a problem.

9
  • If they're allocated dynamically and then stored somewhere and then accessed via references, then your overloads will work fine. You cannot overload operators on pointer types. Commented Aug 6, 2017 at 3:10
  • What is the actual meaning of your class? How large is one instance of it? Commented Aug 6, 2017 at 3:11
  • My class has a character array whose length can vary from a few characters to thousands of characters. No other data members exist, but the class contains a large number of functions (about 60+) Commented Aug 6, 2017 at 3:13
  • @user1637645: What is sizeof(Complex)? Commented Aug 6, 2017 at 3:14
  • 1
    @user1637645 use references instead of pointers whenever possible. The speed of pointers without the dangers of pointing to invalid addresses or the inelegance of manual dereferencing. And if sampleFunc() does not modify c then use const Complex &c (or Complex const &c) instead of Complex &c. The return value should not be a Complex& reference if a new Complex is created, returning by value is the correct way. Commented Aug 6, 2017 at 3:27

2 Answers 2

3

Firstly, you will often be better off avoiding pass by value, and specifying your member functions as accepting a reference

class Complex
{
  public:
     Complex sampleFunc(const Complex &c) { ... }
     Complex operator+(const Complex &c) { ... }
};

The const specifies that the function will not logically change c as far as the caller is concerned - which is often the same effect as passing by value, except that it does not create a copy of the object being passed.

Removing the const allows the object to be changed.

That said, you CAN pass by value to any function you like, if it makes sense to pass a copy of an object to a function rather than a reference.

Second, your preconceptions from using another language are showing, and leading you to a wrong conclusion about C++. Specifically, your belief

This would be a library, so other users would be using my class. Since, most users use:

Complex *ptrObj = new Complex();    // declaration 1

rather than using:

Complex obj;                        // declaration 2

is false. Most C++ developers, given these two choices, will default to using the second form since, in quite a few circumstances, the first form is poor practice in C++ - due to a requirement to delete ptrObj when done, in order to avoid a memory leak, and the potential to forget to do that, particularly in non-trivial code.

Using the code in a library does not change this. As a rough rule (and, as a rough rule, there are some exceptions) if you find yourself writing lots of code that uses pointers in C++ (unless you are writing a version of the standard library) then your design is broken.

Sign up to request clarification or add additional context in comments.

Comments

1

As you described in the comments, your Complex class is basically a variable-length string, and contains a char* plus an int.

The first thing to do, then, is to discourage the users of this class from doing new Complex, because it is not efficient. You are doing dynamic memory allocation within your class, so there is no need to do it outside as well (you're just adding more pointer indirection).

You should write your operators in the conventional way, which is to accept references, not pointers. And users will typically not need to deal with pointers, because your class abstracts the dynamic memory as an implementation detail.

For example:

class Complex
{
public:
    // TODO: define constructors and assignment operator

    Complex sampleFunc(Complex&); // could also return Complex& (*this)
    Complex operator+(const Complex&) const;

private:
    std::unique_ptr<char[]> _data;
    size_t _size;
};

2 Comments

Earlier, I had 2 constructors: Complex(Complex *c) { ... } and Complex(Complex &c) { .... // copy constructor ... }. Should I remove the first one (non-copy-constructor) now?
You should have just one copy constructor: Complex(const Complex&). Note the const, which all copy constructors should have.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.