Метод класса C ++, выполняемый перед другим методом

0

Я использовал этот сайт совсем немного в прошлом, и мне никогда не приходилось публиковать вопрос раньше, но я не уверен, как это просто выразить. Я нахожусь в классе C++ в Devry, на самом деле моя задача выполнения моего проекта выполнена, но я добавляю некоторые элементы для практики.

Поэтому, чтобы пойти с домашним заданием, я добавил дополнительный класс Song. Он имеет 2 частных переменных (заголовок и длину) некоторых базовых конструкторов и перегрузок операций для = и ==. Все работает отлично. Затем я добавил массив класса Song в класс Cd (максимальное количество песен на Cd равно 10). Я создал несколько новых методов для Cd:

  • addSong (Song s);
  • removeSong (Song s);
  • organizeSong(); а также
  • измененный отчет() const;

записывать песни в порядке, исходя из количества выбранных вариантов. Частные значения 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;
}

Снова я ценю попытки сделать код более эффективным или иметь больше смысла, но я уже делаю больше, чем учитель попросил нас. Я просто хочу знать, есть ли очевидная причина того, почему песня удаляется до того, как отчет отобразится в первый раз, даже несмотря на то, что в начале появляется отчет.

  • 0
    Многочисленные проблемы с этим кодом, TBH. 1. Используемая коллекция не должна быть массивом, если вы хотите удалить ее из середины. 2. Report должен использовать цикл for над контейнером, не ограничиваясь какой-либо произвольной переменной. Посмотрите на std::set .
  • 0
    Я уверен, что в эффективности кодов есть много неправильного, однако это не имеет отношения к моему текущему домашнему заданию или тайне того, почему removeSong вступает в силу перед Отчетом. Также removeSong имеет код для организации массива, который отлично работает. Я попробовал использовать список, но есть вещи, с которыми я пока не знаю, как работать, и пока не собираюсь идти так далеко от класса. Итак, я в порядке с вопросами эффективности на данный момент, но это то, что вызывает removeSong перед отчетом?
Теги:

1 ответ

1

Не зная о вашей реализации, было сложно ответить на ваш вопрос, поэтому я написал его, как я полагаю, он должен выглядеть. Однако я сделал несколько улучшений:

  1. 3.14 не означает "3 минуты и 14 секунд". В лучшем случае это означает 3,14 минуты, что составляет 3 минуты и 8,4 секунды. Я изменил это на недвусмысленные примитивы chrono
  2. Удаление песни по значению было неоднозначным из-за нечеткого равенства отношений между песнями. Я заметил, что вы перегрузили operator==, но я не вижу способа, как это можно было бы разумно реализовать. Добавление уникального идентификатора к каждой песне было бы способом его решения, но я не чувствовал к нему права, поэтому я решил удалить по индексу (который также очень хорошо моделирует компакт-диск).
  3. Коллекция не является потокобезопасной. Не забывайте об этом.
  4. Я не знаю, почему 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
    Больше похоже на ... 3 минуты и 8,399999983749288 секунд. Кроме того, этот класс просто не является потокобезопасным, не только потому, что интерфейс не позволяет выполнять запрос / обновление без гонки.
  • 0
    Значения являются произвольными, просто для представления использования переменных и объявления класса. Это базовый класс, в котором я учусь, поэтому мы только сейчас изучаем наследование и состав. Мне никогда не нравилось использовать double для представления времени, но это был выбор учителей, я ценю пример использования хронографа. Я опубликую остальную часть кода, который я использую, и, возможно, он прояснит мой вопрос. Я даже не знаю, что такое threadsafe, но я посмотрю на это. Я знаю, что это не влияет на этот текущий проект.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню