c++operator-overloadingstatic-membersostreamfriend-function

Friend Function cannot access private members in C++


I have created class and trying to overload ostream operator using a friend function but my friend is not able access private members of functions. Please help me figure out the problem. I have created another friend function named doSomething() from here I can call private member but not from overloaded function. Please help me updating overloaded stream insertion function.

Class Header File:

#pragma once
#ifndef MYSTRING_H
#define MYSTRING_H


class MyString
{
    char* str; 
    int length;
public:
    MyString();
    MyString(const char*);
    ~MyString();
    MyString (const MyString &Obj);
    void Display() const;
    int GetLength() const;
    const MyString& operator = (const MyString&);
    friend ostream& operator << (ostream &output,MyString&s);
    friend void doSomething();
};
#endif

Class CPP File:

#define _CRT_SECURE_NO_WARNINGS
#include "MyString.h"
#include <iostream>

using namespace std;

MyString::MyString() {
    length = 0;
    str = new char[1];
    str[length] = '\0';
}

MyString::MyString(const char* cString) {
    length=strlen(cString);
    str = new char[length+1];
    strcpy(str,cString);
    str[length] = '\0';
}

MyString::~MyString() {
    delete[] str;
    str = nullptr;
    length = 0;
}

MyString::MyString(const MyString& Obj) {
    
    length = Obj.length;
    str = new char[length+1];
    strcpy(str, Obj.str);
    str[length] = '\0';
}

void MyString::Display() const {
    cout << str << endl;
}

int MyString::GetLength() const  {
    return length;
}

const MyString& MyString::operator = (const MyString& Obj) {
    this->~MyString();
    length = Obj.length;
    str = new char[length + 1];
    strcpy(str, Obj.str);
    return *this;
}

Main CPP:

#define _CRT_SECURE_NO_WARNINGS
#include "MyString.h"
#include <iostream>
using namespace std;



ostream &operator << (ostream& output, MyString s) {
        
        output << s.length;
        return output;
}
void doSomething() {
    MyString s;
    s.length;
}

int main() {

    return 0;
}

Solution

  • There are 2 problems with your code.

    Mistake 1: You have not included iostream in MyString.h

    Solution to mistake 1

    MyString.h

    #pragma once
    #ifndef MYSTRING_H
    #define MYSTRING_H
    #include <iostream> //ADDED THIS
    
    class MyString
    {
        char* str; 
        int length;
    public:
        MyString();
        MyString(const char*);
        ~MyString();
        MyString (const MyString &Obj);
        void Display() const;
        int GetLength() const;
        const MyString& operator = (const MyString&);
        friend std::ostream& operator << (std::ostream &output,MyString&s); //ADDED STD::  here
        friend void doSomething();
    };
    #endif
    

    Mistake 2: You have a missing & symbol while defining operator<< in main.cpp.

    Solution to Mistake 2

    main.cpp

    #define _CRT_SECURE_NO_WARNINGS
    #include "MyString.h"
    #include <iostream>
    using namespace std;
    
    
    ostream &operator << (ostream& output, MyString &s) {//ADDED & HERE
            
            output << s.length;
            return output;
    }
    void doSomething() {
        MyString s;
        s.length;
    }
    
    int main() {
    
        return 0;
    }
    

    Additionally, i have added #inlcude <cstring> in MyString.cpp. So MyString.cpp now looks like:

    MyString.cpp

    #define _CRT_SECURE_NO_WARNINGS
    #include "MyString.h"
    #include <iostream>
    #include <cstring>
    using namespace std;
    
    MyString::MyString() {
        length = 0;
        str = new char[1];
        str[length] = '\0';
    }
    
    MyString::MyString(const char* cString) {
        length=strlen(cString);
        str = new char[length+1];
        strcpy(str,cString);
        str[length] = '\0';
    }
    
    MyString::~MyString() {
        delete[] str;
        str = nullptr;
        length = 0;
    }
    
    MyString::MyString(const MyString& Obj) {
        
        length = Obj.length;
        str = new char[length+1];
        strcpy(str, Obj.str);
        str[length] = '\0';
    }
    
    void MyString::Display() const {
        cout << str << endl;
    }
    
    int MyString::GetLength() const  {
        return length;
    }
    
    const MyString& MyString::operator = (const MyString& Obj) {
        this->~MyString();
        length = Obj.length;
        str = new char[length + 1];
        strcpy(str, Obj.str);
        return *this;
    }
    

    The program now works(compiles) as can be verified here.

    Additional Problem

    You should not call the destructor(the way you're calling on the current object) from inside operator='s body.

    You can solve this by using @PaulMcKenzie's suggestion in the comments of your original question.

    const MyString& MyString::operator = (const MyString& Obj)
    {  MyString temp(Obj); 
       std::swap(temp.str, str); 
       std::swap(temp.length, length); 
      
       return *this;
    }