Я использовал этот сайт совсем немного в прошлом, и мне никогда не приходилось публиковать вопрос раньше, но я не уверен, как это просто выразить. Я нахожусь в классе C++ в Devry, на самом деле моя задача выполнения моего проекта выполнена, но я добавляю некоторые элементы для практики.
Поэтому, чтобы пойти с домашним заданием, я добавил дополнительный класс Song. Он имеет 2 частных переменных (заголовок и длину) некоторых базовых конструкторов и перегрузок операций для = и ==. Все работает отлично. Затем я добавил массив класса Song в класс Cd (максимальное количество песен на Cd равно 10). Я создал несколько новых методов для Cd:
записывать песни в порядке, исходя из количества выбранных вариантов. Частные значения Cd выбора и времени воспроизведения теперь связаны с общим количеством песен и общей длиной этих песен соответственно. Все работает нормально. removeSong берет указанную песню из списка, затем вызывает organizSong, чтобы установить оставшиеся песни в самые низкие значения в массиве. Однако кажется, где бы я ни называл removeSong (Song s), он удаляет его, прежде чем что-либо записывает в программу. Таким образом, следующий код будет извлекать информацию из Cd, но только одну из песен, несмотря на то, что метод removeSong вызывается после метода Report. у кого есть идеи, почему это так?
Song s1("Hey Jude", 4.52);
Song s2("The song of Pie", 3.14);
Cd c1 ("Beatles", "Capitol");
c1.addSong(s1);
c1.addSong(s2);
cout<< "Using object directly: \n";
c1.Report();
c1.removeSong(s1);
метод Report выглядит следующим образом:
void Cd::Report () const
{
cout<< "Performers: " << performers << endl << "Label: " <<label << endl << "Selections: " << selections <<endl << "Playtime: " << playtime << endl;
for(int i = 0; i < selections; i++)
{
cout << "Song " << i+1 << ": " << song[i].getTitle() << " Length: " << song[i].getLength() << endl;
}
}
для уточнения. Я тестировал это с большим количеством песен, и без вызова метода removeSong, и он выпишет все песни в массиве.
EDIT ** Я добавляю остальную часть своего кода, чтобы надеяться, прояснить мой вопрос. Я пока не заинтересован в том, чтобы сделать его потокобезопасным или более эффективным, у него нет никакой цели, кроме демонстрации наследования и состава классов моему преподавателю, оба из которых он уже делает за пределами того, что задает наше задание. Я ценю комментарии о том, как сделать код лучше и будет изучать эти вещи, но я пытаюсь выяснить, почему removeSong производит вывод отчета, когда Report приходит перед removeSong в основном коде. Я тестировал различные методы и перегрузки, и все они работают так, как они предполагают, это только время, когда removeSong происходит, что меня интересует. Он удаляет правильную песню и правильно упорядочивает существующие песни, она просто делает это скоро: до вызова первого отчета. (Мне нужно изменить верхний регистр в отчете для согласованности). Я в основном уверен, что это нечто основное, что мне не хватает в этом нового.
основной код:
// GSP125_Davis_lab4_partA.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <conio.h>
#include "classic.h"
#include <string.h>
///Prototypes
void Bravo(const Cd & disk);
Song s1("Hey Jude", 4.52);
Song s2("the Song of Pie",3.14);
Song s3("National Anthem", 5.55);
char* userInput = "null";
char str[20] = "null";
bool bol_end = false;
int main()
{
Cd c1 ("Beatles", "Capitol");
c1.addSong(s1);
c1.addSong(s2);
c1.addSong(s3);
Cd *pcd = &c1;
Classic c2("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Phillips");
c2.addSong(s2);
c2.addSong(s3);
c2.addSong(s1);
cout << "Using object directly:\n";
//this is where the code seems to have an issue. as you see Report is called
//then after c1.removeSong(s1) is called. s1 is removed properly but this first
// c1.Report() reflects the changes removeSong makes.
c1.Report();
c2.Report();
c1.removeSong(s1);
cout << "Using type Cd method for cd object:\n";
pcd->Report();
pcd = &c2;
pcd-> Report();
cout<< "Calling a function with a Cd reference argument:\n";
Bravo(c1);
Bravo(c2);
cout << "Testing assignment: \n";
Classic copy;
copy = c2;
copy.Report();
cout << "Press any key to continue...";
_getch();
return 0;
}
void Bravo(const Cd & disk)
{
disk.Report();
}
Cd.cpp
#include "StdAfx.h"
#include "cd.h"
Cd::Cd(char * s1, char * s2)
{
strcpy(performers, s1);
strcpy(label, s2);
selections = 0;
playtime = 0;
for(int i = 0; i < songLimit; i++)
{
song[i] = Song();
}
}
Cd::Cd(const Cd & d)
{
strcpy(performers, d.performers);
strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
for(int i = 0; i < songLimit; i++)
{
song[i] = d.song[i];
}
}
Cd::Cd()
{
strcpy(performers, "None");
strcpy(label, "No one");
selections = playtime = 0;
for(int i = 0; i < songLimit; i++)
{
song[i] = Song();
}
}
Cd::~Cd(void)
{
}
void Cd::Report () const
{
cout<< "Performers: " << performers << endl << "Label: " <<label << endl << "Selections: " << selections <<endl << "Playtime: " << playtime << endl;
for(int i = 0; i < selections; i++)
{
cout << "Song " << i+1 << ": " << song[i].getTitle() << " Length: " << song[i].getLength() << endl;
}
}
void Cd::addSong(Song s)
{
for (int i = 0; i < songLimit; i++)
{
if (song[i].getTitle() == "none")
{
song[i] = s;
selections++;
playtime+= s.getLength();
break;
}
}
}
void Cd::removeSong(Song s)
{
for (int i = 0; i < songLimit; i++)
{
if(song[i] == s)
{
song[i] = Song();
selections--;
playtime-= s.getLength();
break;
}
}
organizeSong();
}
void Cd::organizeSong()
{
int empty = -1;
for (int i = 0; i < songLimit; i++)
{
if(song[i].getTitle() == "none" && empty == -1)
{
empty = i;
}
else if (empty != -1)
{
song[empty] = song[i];
song[i] = Song();
empty = i;
}
}
}
Cd & Cd::operator=(const Cd & d)
{
strcpy(performers, d.performers);
strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
for(int i = 0; i < songLimit; i++)
{
song[i] = d.song[i];
}
return *this;
}
Song.cpp
#include "StdAfx.h"
#include "Song.h"
Song::Song(char* s, double l)
{
title = s;
length = l;
}
Song::Song(const Song & s)
{
title = s.title;
length = s.length;
}
Song::Song()
{
title = "none";
length = 0;
}
Song::~Song(void)
{
}
char* Song::getTitle() const
{
return title;
}
double Song::getLength() const
{
return length;
}
Song & Song::operator=(const Song & s)
{
title = s.title;
length = s.length;
return *this;
}
bool & Song::operator==(const Song & s)
{
bool result = false;
if (title == s.title && length == s.length)
{
result = true;
}
return result;
}
Снова я ценю попытки сделать код более эффективным или иметь больше смысла, но я уже делаю больше, чем учитель попросил нас. Я просто хочу знать, есть ли очевидная причина того, почему песня удаляется до того, как отчет отобразится в первый раз, даже несмотря на то, что в начале появляется отчет.
Не зная о вашей реализации, было сложно ответить на ваш вопрос, поэтому я написал его, как я полагаю, он должен выглядеть. Однако я сделал несколько улучшений:
3.14
не означает "3 минуты и 14 секунд". В лучшем случае это означает 3,14 минуты, что составляет 3 минуты и 8,4 секунды. Я изменил это на недвусмысленные примитивы chrono
operator==
, но я не вижу способа, как это можно было бы разумно реализовать. Добавление уникального идентификатора к каждой песне было бы способом его решения, но я не чувствовал к нему права, поэтому я решил удалить по индексу (который также очень хорошо моделирует компакт-диск).report
был заглавным, но я изменил это, чтобы сохранить согласованность.Я не знал, как должна работать реорганизация внутри компакт-диска, поэтому я просто пропустил эту часть.
#include <iostream>
#include <list>
#include <functional>
#include <chrono>
#include <string>
#include <stdexcept>
#include <iterator>
// C++14-like shim
// in C++14 just use min and s
constexpr std::chrono::minutes operator "" _min(unsigned long long m) {
return std::chrono::minutes(m);
}
constexpr std::chrono::seconds operator "" _s(unsigned long long s) {
return std::chrono::seconds(s);
}
class Song {
public:
std::string title;
std::chrono::seconds length;
Song(std::string title, std::chrono::seconds length) :
title(std::move(title)), length(length) { }
};
class Cd {
std::list<std::reference_wrapper<Song>> songs;
std::string performer, title;
public:
void addSong(Song & s) {
songs.push_back(std::ref(s));
}
void removeSong(unsigned n) {
if (n >= songs.size())
throw std::out_of_range("The song of given index doesn't exist on that album");
songs.erase(std::next(songs.begin(), n));
}
void report() const {
std::cout << title << ", " << performer << '\n';
for (auto const& song : songs) {
std::cout << song.get().title << " "
<< song.get().length.count() / 60 << ":"
<< song.get().length.count() % 60 << '\n';
}
std::cout << std::endl;
}
Cd(std::string performer, std::string title) :
performer(std::move(performer)), title(std::move(title))
{ }
};
int main() {
Song s1("Hey Jude", 4_min + 52_s);
Song s2("The song of Pie", 3_min + 14_s);
Cd c1 ("Beatles", "Capitol");
c1.addSong(s1);
c1.addSong(s2);
c1.report();
// this doesn't work anymore because of the reasons described above
//c1.removeSong(s1);
c1.removeSong(0);
c1.report();
}
1.
Используемая коллекция не должна быть массивом, если вы хотите удалить ее из середины.2.
Report
должен использовать цикл for над контейнером, не ограничиваясь какой-либо произвольной переменной. Посмотрите наstd::set
.