This is my first time writing C++, so I would appreciate advice in the areas of:

 - Code style (naming conventions, indentation, etc)
 - Memory usage (am I performing unnecessary object copies?)
 - Class design (move constructors, destructors, etc, are they necessary?)
 - Correct usage of standard library functions (especially the string parsing part)

###complex.h:

    #ifndef COMPLEX_H
    #define COMPLEX_H

    #include <string>

    class Complex
    {
    private:
        double real_;
        double imag_;

    public:
        Complex();
        Complex(const Complex& obj);
        Complex(const std::string& str);
        Complex(double real);
        Complex(double real, double imag);
        double real() const;
        double imaginary() const;
        double argument() const;
        double modulus() const;
        Complex conjugate() const;
        Complex pow(double power) const;
        std::string toString() const;
        Complex operator+(const Complex& rhs) const;
        Complex operator-(const Complex& rhs) const;
        Complex operator*(const Complex& rhs) const;
        Complex operator/(const Complex& rhs) const;
        bool operator==(const Complex& rhs) const;
        bool operator!=(const Complex& rhs) const;
    };

    #endif

###complex.cpp:

    #include <cmath>
    #include <sstream>
    #include <regex>

    #include "complex.h"

    Complex::Complex(const Complex& obj) : Complex(obj.real_, obj.imag_) { }

    Complex::Complex(const std::string& str) {
        double real = 0.0, imag = 0.0;
        std::regex realRegex("^(-)?\\s*(\\d+(\\.\\d+)?)$");
        std::regex imagRegex("^(-)?\\s*(\\d+(\\.\\d+)?)i$");
        std::regex bothRegex("^(-)?\\s*(\\d+(\\.\\d+)?)\\s*([-+])\\s*(\\d+(\\.\\d+)?)i$");
        std::smatch match;
        if (std::regex_match(str.begin(), str.end(), match, realRegex)) {
            real = std::atof(match[2].str().c_str());
            if (match[1].matched) {
                real = -real;
            }
        } else if (std::regex_match(str.begin(), str.end(), match, imagRegex)) {
            imag = std::atof(match[2].str().c_str());
            if (match[1].matched) {
                imag = -imag;
            }
        } else if (std::regex_match(str.begin(), str.end(), match, bothRegex)) {
            real = std::atof(match[2].str().c_str());
            imag = std::atof(match[5].str().c_str());
            if (match[1].matched) {
                real = -real;
            }
            if (match[4].str() == "-") {
                imag = -imag;
            }
        } else {
            throw std::runtime_error("Invalid number format");
        }
        real_ = real;
        imag_ = imag;
    }

    Complex::Complex() : Complex(0.0) { }

    Complex::Complex(double real) : Complex(real, 0.0) { }

    Complex::Complex(double real, double imag) : real_(real), imag_(imag) { }

    double Complex::real() const {
        return real_;
    }

    double Complex::imaginary() const {
        return imag_;
    }

    double Complex::argument() const {
        return std::atan2(imag_, real_);
    }

    double Complex::modulus() const {
        return std::sqrt(real_ * real_ + imag_ * imag_);
    }

    Complex Complex::conjugate() const {
        Complex result(real_, -imag_);
        return result;
    }

    Complex Complex::pow(double power) const {
        double mod = modulus();
        double arg = argument();
        mod = std::pow(mod, power);
        arg *= power;
        double real = mod * std::cos(arg);
        double imag = mod * std::sin(arg);
        Complex result(real, imag);
        return result;
    }

    std::string Complex::toString() const {
        std::stringstream fmt;
        if (imag_ == 0) {
            fmt << real_;
        } else if (real_ == 0) {
            fmt << imag_ << "i";
        } else {
            fmt << real_;
            if (imag_ < 0) {
                fmt << " - " << -imag_;
            } else {
                fmt << " + " << imag_;
            }
            fmt << "i";
        }
        return fmt.str();
    }

    Complex Complex::operator+(const Complex& rhs) const {
        Complex result(real_ + rhs.real_, imag_ + rhs.imag_);
        return result;
    }

    Complex Complex::operator-(const Complex& rhs) const {
        Complex result(real_ - rhs.real_, imag_ - rhs.imag_);
        return result;
    }

    Complex Complex::operator*(const Complex& rhs) const {
        double newReal = real_ * rhs.real_ - imag_ * rhs.imag_;
        double newImag = real_ * rhs.imag_ + imag_ * rhs.real_;
        Complex result(newReal, newImag);
        return result;
    }

    Complex Complex::operator/(const Complex& rhs) const {
        double denom = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_;
        double newReal = (real_ * rhs.real_ + imag_ * rhs.imag_) / denom;
        double newImag = (imag_ * rhs.real_ - real_ * rhs.imag_) / denom;
        Complex result(newReal, newImag);
        return result;
    }

    bool Complex::operator==(const Complex& rhs) const {
        return real_ == rhs.real_ && imag_ == rhs.imag_;
    }

    bool Complex::operator!=(const Complex& rhs) const {
        return !(*this == rhs);
    }