• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Przeciążenie operatora+ łączenie dwóch łańcuchów

Aruba Cloud VPS - 50% taniej przez 3 miesiące!
0 głosów
1,024 wizyt
pytanie zadane 3 listopada 2018 w C i C++ przez Sic Dyskutant (8,510 p.)
edycja 3 listopada 2018 przez Sic

Witam w zadaniu miałem stworzyć przeciążenie operatora+, który ma połączyć ze sobą dwa łańcuchy. Wykorzystałem do tego funkcje strncat() i tu pojawia się moje pytanie, ponieważ zrobiłem wszystko zgodnie z dokumentem funkcji a jednak pojawia się błąd: "wartość początkowa odwołania do wartości niebędącej stała musi być l-wartością". Próbowałem również wykorzystać funkcję strcat(), jednak pojawia się ten sam błąd, proszę o podpowiedź.

String & String::operator+(const String & plus) //przeciążenie operatora+
{
	return strncat(str, plus.str, std::strlen(str));
}

 

komentarz 3 listopada 2018 przez adrian17 Mentor (351,140 p.)
Pokażesz więcej kodu, definicję klasy? Bo bez kontekstu to ogólnie nie wydaje się mieć sensu.
komentarz 3 listopada 2018 przez RafalS VIP (122,820 p.)
Obawiam sie, że zwracanie referencji do obiektu tymczasowego nigdy nie bedzie mialo sensu :D
komentarz 3 listopada 2018 przez adrian17 Mentor (351,140 p.)
(fakt, natomiast strncat też wygląda dość podejrzanie sam z siebie)
komentarz 3 listopada 2018 przez j23 Mędrzec (195,260 p.)
Implementacja tego operatora jest bez sensu (i jest błędna).

1 odpowiedź

0 głosów
odpowiedź 3 listopada 2018 przez RafalS VIP (122,820 p.)

Troszke nagmatwałeś.

Sam błąd oznacza, że nie możesz zainicjować referencji niestałą r-wartoscia:

//blad kompilacji
String& s = String();
//wszystko cacy
const String& s2 = String();

r-wartość w tym przypadku to coś ulotnego co w normalnych warunkach przestaje istnieć w kolejnej linijce. Łapiąc ją przy pomocy referencji możesz przedłużyć jej życie, ale na modyfikowanie tego ulotnego obiektu jezyk juz nie pozwala.

Ale moment? Skąd u Ciebie rwartosci?

strncat zwraca char * a Twoja funkcja deklaruje zwracanie String& co powoduje, że tak na prawde zwracasz:

    return String(strncat(str, plus.str, std::strlen(str)));

o ile istnieje konstruktor String(char *).

Żeby umożliwić łańcuchy możesz zwrócić obiekt przez wartość. Bo tak powinien działać operator +. Zwracać nowy obiekt a nie modyfikowac operandy:

string s1 = "paprykarz";
string s2 = "szczecinski ";
string s3 = s1 + s2;
//spodziewasz sie, ze
s1 == "paprykarz" && s2 == "szczecinski " && s3 == "paprykarz szczecinski"
//a w tym momencie s3 co prawda bedzie sie zgadzac ale s2 tez bedzie zmodyfikowane
komentarz 3 listopada 2018 przez Sic Dyskutant (8,510 p.)

@RafalS

Zrobiłem jak powiedziałeś i zadziałało, jednak w zadaniu podany jest już gotowy 'main':

#include <iostream>
#include "string2.h"

int main()
{
	String s1(" i ucze sie C++.");
	String s2 = "Podaj swoje imie: ";
	String s3; 
	std::cout << s2; //przeciążenie operatora <<
	std::cin >> s3;  //przeciążenie operatora >>
	s2 = "Mam na imie " + s3; //przeciążenie operatora = i +
	std::cout << s2 << ".\n";
	s2 = s2 + s1;
	s2.stringup(); //zmiana liter ciągu na wielkie
	std::cout << "Ciag\n" << s2 << "\nzawiera " << s2.has("A") << " 'A'.\n";
	s1 = "czerwona"; //String(const char *), a potem String & operator=(const String &)
	String rgb[3] = { String(s1), String("zielona"), String("niebieska" };
	std::cout << "Podaj nazwę barwy podstawowej: ";
	String ans;
	bool success = false;
	while (std::cin >> ans)
	{
		ans.stringlow(); //zamiana liter w ciągu na małe
		for (int i = 0; i < 3; i++)
		{
			if (ans == rgb[i])
			{
				std::cout << "Prawidłowo!\n";
				success = true;
				break;
			}
		}
		if (success)
			break;
		else
			std::cout << "Sprobuj ponownie!\n";
	}
	std::cout << "Zegnaj\n";
	return 0;
}

Podczas kompilacji występuje mi błąd:

" dwuargumentowy "+": nie znaleziono żadnego globalnego operatora, który przyjmuje typ "String" (lub nie istnieje akceptowalna konwersja)"

Wiem co oznacza ale nie rozumiem go i nie wiem w jaki sposób go poprawić (gdy próbuje dodać char i objekt klasy pokazuje mi, że musi być typ całkowitoliczbowy).

komentarz 3 listopada 2018 przez RafalS VIP (122,820 p.)
Bez Twojego kodu nie jestem w stanie pomóc.
komentarz 3 listopada 2018 przez Sic Dyskutant (8,510 p.)

class String
{
	private:
		char * str;					//wskaźnik ciągu
		int len;					//długość ciągu ?
		static int num_string;		//liczba obiektów klasy ?
		static const int CINLIM = 80; //limit długości ciągu na wejściu
	public:
		//kontruktory
		String();					//kontruktor domyślny
		String(const char*);		//konstruktor 
		String(const String &);		//kontruktor kopiujący
		~String();					//destruktor
		int length() const { return len; }
		
		//metody
		void stringup();			//zamiana liter ciągu na duże
		void stringlow();			//zamiana liter ciągu na małe
		int has(const char *);			//liczba wystąpień znaku w ciągu

		//przeciążenia
		String & operator=(const String &); //przeciążenie operatora=
		String & operator=(const char *);
		char & operator[](int);
		const char & operator[](int) const;
		String & operator+(const String &); //przeciążenie operatora+
		

		//zaprzyjaźnione
		friend bool operator==(const String &, const String &);
		friend std::ostream & operator<<(std::ostream &, const String &);
		friend std::istream & operator>>(std::istream &, String &);

};
#endif
//definicja konstruktorów
String::String()
{
	len = 4;
	str = new char[len + 1];
	str[0] = NULL;
	num_string++;
}

String::String(const char * sign)
{
	len = std::strlen(sign);
	str = new char[len + 1];
	std::strcpy(str, sign);
	num_string++;
}

String::String(const String & st)
{
	num_string++;
	len = st.len;
	str = new char[len + 1];
	std::strcpy(str, st.str);
	
}

String::~String()
{
	--num_string;
	delete[] str;
}

//definicja przeciążeń

String & String::operator=(const String & string) //przeciążenie operatora=
{
	if (this == &string)
		return *this;
	delete[] str;
	len = string.len;
	str = new char[len + 1];
	std::strcpy(str, string.str);
	return *this;
}

String & String::operator=(const char * sign) //przeciążenie operatora=
{
	delete[] str;
	len = std::strlen(sign);
	str = new char[len + 1];
	std::strcpy(str, sign);
	return *this;
}
char & String::operator[](int index) //przeciążenie operatora indeksowania
{
	return str[index];
}

const char & String::operator[](int index) const //przeciążenie operatora indeksowania
{
	return str[index];
}

String & String::operator+(const String & plus) //przeciążenie operatora+
{
	//String object = strncat(str, plus.str, 80);
	return object;
}

//zaprzyjaźnione przeciążenia

bool operator==(const String & st, const String & st2)
{
	return (std::strcmp(st.str, st2.str) == 0);
}

std::ostream & operator<<(std::ostream & os, const String & string)
{
	os << string.str;
	return os;
}

std::istream & operator>>(std::istream & is, String & string)
{
	char temp[String::CINLIM]; // do składowych statycznych należy się odnosić za pomocą 'operatora zasięgu'
	is.get(temp, String::CINLIM);
	if (is)
		string = temp;
	while (is && is.get() != '\n')
		continue;
	return is;
}

//metody dodatkowe

/* DO POPRAWY !
void String::stringup()			//zamiana liter ciągu na duże
{
	for (int i = 0; i < std::strlen(str); i++)
		toupper(i);
}
void String::stringlow()		//zamiana liter ciągu na małe
{
	for (int i = 0; i < std::strlen(str); i++)
		tolower(i);
}
*/
int String::has(const char * sign)
{
	int score = 0;
	for (int i = 0; i < std::strlen(str); i++)
	{
		if (sign[i] == str[i])
			score++;
	}
	return score;
}

Definicje wymagają poprawek, których dokonam po rozwiązaniu tego problemu.

komentarz 3 listopada 2018 przez RafalS VIP (122,820 p.)
	s2 = "Mam na imie " + s3; //przeciążenie operatora = i +

bo nie masz ngdzie takiego przeciążenia:

String operator(const char* lhs, const String& rhs)

A na dobrą sprawe wszysto by zadzialalo dzieki niejawnym konwersją gdyby operator:

String & String::operator+(const String & plus);

był zdefiniowany jako wolna funkcja a nie metoda w ten sposob:

String & operator+(const String & lhs, const String& rhs);

 

komentarz 3 listopada 2018 przez Sic Dyskutant (8,510 p.)
Jako wolna funkcja ?
komentarz 3 listopada 2018 przez RafalS VIP (122,820 p.)
Nie. Operator mozesz przeladowac jako metode wewnątrz klasy albo zwykla funkcje.
komentarz 3 listopada 2018 przez Sic Dyskutant (8,510 p.)
Metodę tak wiem, ale jeżeli chodzi o funkcję to można w klasie i strukturze przeciążać za pomocą zaprzyjaźnionych.
komentarz 3 listopada 2018 przez RafalS VIP (122,820 p.)
Nic nie musisz zaprzyjaźniać.
komentarz 4 listopada 2018 przez Sic Dyskutant (8,510 p.)
To już nie wiem o co chodzi.
komentarz 4 listopada 2018 przez RafalS VIP (122,820 p.)
Generalnie nie musisz, ale teraz zauważyłem że nie dobierzesz się do str, wiec jednak przyjazn
komentarz 4 listopada 2018 przez Sic Dyskutant (8,510 p.)

To swoją drogą, w dodatku zorientowałem się że są potrzebne zdefiniowane dwa różne przeciążenie tego operatora.

#1 wywołanie w pliku 'main'

s2 = s2 + s1;

a tutaj jego definicja (działa poprawnie)

String & String::operator+(const String & plus) //przeciążenie operatora+
{
	String object = strcat(str, plus.str); //strcat() łączy ze sobą dwa łańcuchy
	return object;
}

#2 z tym mam problem nie mogę dobrać odpowiedniej definicji

s2 = "Mam na imie " + s3; //przeciążenie operatora = i +
String & operator+(char * sign, const String & plus)
{
	String object = strcat(sign, plus.str);
	return object;

}

Próbowałem definiować też z argumentem "const char*" jednak za każdym razem był błąd. Zamiast korzystać z funkcji strcat() lub strncat() starałem się zwyczajnie je połączyć niestety wszystko próby okazały się niepowodzeniem.

komentarz 18 marca 2019 przez Poczatkujacy127 Nowicjusz (120 p.)

Robię bardzo podobnie i mam identyczny problem.

Próbuję jeszcze tak (to jest funkcja zaprzyjaźniona, potrzebna aby połączyć "Mam na imię... " z obiektem s3. 

String operator + (const char *c,  String &s)
 {

    String temp;
    temp.len = strlen(c) + s.len;
    temp.str = new char[temp.len + 1];
    strcpy(temp.str, c);
    strcat(temp.str, s.str);
    return temp;



 }

Program się kompiluje, ale za wpisanym imieniem wyskakują śmieci i dalej sie sypie. 
Czy komuś się w ogóle udało zrobić to zadanie? Szukam od 3 dni i nie mogę znaleźć, chyba się poddam. 

Podobne pytania

0 głosów
1 odpowiedź 259 wizyt
+1 głos
1 odpowiedź 758 wizyt
pytanie zadane 19 czerwca 2021 w C i C++ przez wndtcw Nowicjusz (130 p.)
+1 głos
2 odpowiedzi 385 wizyt
pytanie zadane 14 czerwca 2021 w C# przez everstudybee Użytkownik (670 p.)

93,187 zapytań

142,203 odpowiedzi

322,013 komentarzy

62,513 pasjonatów

Advent of Code 2024

Top 15 użytkowników

  1. 2365p. - dia-Chann
  2. 2326p. - Łukasz Piwowar
  3. 2315p. - Łukasz Eckert
  4. 2301p. - CC PL
  5. 2269p. - Tomasz Bielak
  6. 2235p. - Łukasz Siedlecki
  7. 2232p. - rucin93
  8. 2006p. - Michal Drewniak
  9. 1946p. - Adrian Wieprzkowicz
  10. 1901p. - Mikbac
  11. 1744p. - rafalszastok
  12. 1734p. - Anonim 3619784
  13. 1733p. - Marcin Putra
  14. 1586p. - Dawid128
  15. 1480p. - ssynowiec
Szczegóły i pełne wyniki

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...