Переделать код с C++ под C#

303
25 апреля 2017, 05:09

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

#include "stdafx.h"
#include <iostream>
struct element
{
    char a;
    element *next;
};
class list
{
    public:
    list();
    void add(char c);
    explicit list(char c);
    void operator+(char c);
    void operator--(int i);
    bool operator == (list &l);
    void print();
    ~list();
    private:
    element *head;
    int count;
};
void list::print()
{
    if (!head) std::cout << "List is empty\n";
    else
    {
    element *h, *t;
    h = head;
    do
    {
        std::cout << h->a << " ";
        t = h->next;
        h = t;
    } while (h);
    std::cout << "\n";
    }
}
void list::add(char c)
{
    if (head == NULL)
    {
    head = new element;
    head->a = c;
    head->next = NULL;
    count = 1;
    }
    else
    {
    element *h;
    h = new element;
    h->a = c;
    h->next = head;
    head = h;
    count++;
    }
}
list::list()
{
    head = NULL;
    count = 0;
}
list::list(char c)
{
    head = new element;
    head->a = c;
    head->next = NULL;
    count = 1;
}
void list::operator+(char c)
{
    add(c);
}
void list::operator--(int i)
{
    if (!head->next)
    {
    element *h;
    h = head;
    head = h->next;
    delete h;
    count--;
    }
    else std::cout << "List is empty\n";
}
list::~list()
{
    element *h;
    if (head)
    {
    do
    {
        h = head;
        head = h->next;
        delete h;
    } while (head);
    }
}
bool list::operator== (list &l)
{
    if ((!head) || (!l.head)) std::cout << "Some List is empty\n";
    else
    {
    if (count == l.count) return true;
    }
    return false;
}

int main()
{
    list ch1('a'), ch2('c');
    ch1.print();
    ch2.print();
    ch1 + 'b';
    ch2 + 'd';
    ch1.print();
    ch2.print();
    if (ch1 == ch2) std::cout << "Are equal\n";
    else std::cout << "Not equal\n";
}
Answer 1

Это не такая простая задачка. Т.е. ее тупо в лоб решить нельзя. По мне гораздо проще не портировать код, а заново написать. Итак, какие проблемы:

  1. C# не поддерживает перегрузку многих операторов. Но вроде указанные вами операторы можно перегрузить.
  2. Указатели в управляемом C# коде запрещены. Но это не проблема, все экземпляры объектов и структур являются ссылками (аналог & в C++).

Чтоб совсем не делать за вас всю работу (попробуйте сами поковырять C#), сделал только интерфейс. Код уж сами впишите (как в C++ нельзя выносить объявления, объявление и определение метода должно быть в одном месте)

    //к сожалению в структурах запрещены циклические ссылки, но ими никто в c# не пользуется
    //имена классов и членов с большой буквы (так принято)
    class Element
    {
        //не данные, а свойства (так принято)
        //но если не нужно, можно убрать '{ get; set; }'
        public char A { get; set; }
        public Element Next { get; set; }
    };
    class List
    {
        //нельзя как в c++ писать 'public:', вы должны перед каждым методом писать 'public'
        //private - по умолчанию, его можно не писать
        //конструктор
        public List()
        {
        }
        //деструкторов в c# нет: тут автоматическая сборка мусора
        //~list();
        /// <summary>
        /// Коментарии в таком прикольном виде пишем
        /// Добавление элемента в список
        /// </summary>
        /// <param name="c">данные</param>
        public void Add(char c)
        {
        }
        //не могу написать оператор, вместо него будет функция
        //public explicit List(char c)
        public void CreateFromChar(char c)
        {
        }
        //оказывается все операторы должны быть статические, так что добавляем List в первый аргумент
        //вроде не ругается, но я бы через функцию сделал
        public static List operator +(List l, char c)
        {
            return null;
        }
        public static List operator --(List l)
        {
            return null;
        }
        public static bool operator ==(List l1, List l2)
        {
            return false;
        }
        //оператор '==' должен быть вместе с '!='
        public static bool operator !=(List l1, List l2)
        {
            return true;
        }
        //эти два метода тоже придется реализовать, иначе на '==' ругается
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        public void Print()
        {
        }

        //приватные члены, можем ключевое слово 'private' опустить
        //опять же оформил как свойства, но можем и как обычные данные сделать
        Element Head { get; set; }
        int Count { get; set; }
    }

Update: как реализовать методы Equals и GetHashCode

Это два разных метода для поддержки операций сравнения в C#, у них нет аналогов в C++.

Самый простой - это Equals. Он принимает на вход другой объект того же типа и возвращает true, если объект равен this и false, если не равен. Логика метода - это уже ваше дело. Можно считать, что этот метод тоже самое что и оператор '==' в C++ (обычно реализуют 'Equals', а '==' не реализуют, иначе непонятно какой из них используется в сравнении):

class List
{
    public override bool Equals(object obj)
    {
        return true; //напишите здесь правильное сравнение (можно вызвать '==')
    }
}
List l1 = new List();
List l2 = new List();
Console.WriteLine(l1.Equals(l2)); //true
//можно было бы написать 'l1 == l2', 
//но из-за присутствия оператора '==' в классе, метод Equals не вызовется

GetHashCode() - не имеет аналога в C++. В C# он нужен для правильной работы словарей, они же - ассоциативные массивы. Словарь хранит объекты в соответсвии с их ключами, а ключами в C# являются целые числа. В JavaScript, например, ключами являются строки. В вашем случае можно реализовать GetHashCode() как объединение GetHashCode() для каждого элемента List:

public override int GetHashCode()
{
    var e = this.Head;
    int res = 0;
    int mul = 1;
    while (e != null)
    {
        res += e.A.GetHashCode() * mul;
        e = e.Next;
        mul *= 17; //волшебное число
    }
    return res;
}
var l1 = new List();
l1.Add('a');
l1.Add('b');
var l2 = new List();
l2.Add('b');
l2.Add('a');
var d = new Dictionary<List, bool>();
d.Add(l1, true);
Console.WriteLine(d.ContainsKey(l1)); //true
Console.WriteLine(d.ContainsKey(l2)); //false
READ ALSO
Библиотека JS методов для Awesomium

Библиотека JS методов для Awesomium

Нужно реализовать ряд методов, взаимодействующих с веб-страницей на JS для выполнения в Awesomium, такие как найти элемент на странице по XPath, кликнуть...

320
DispatcherTimer первый вызов Tick сразу при старте C#

DispatcherTimer первый вызов Tick сразу при старте C#

Как сделать, чтобы при запуске таймера он сразу выполнил код в прикрепленном методе, а не дожидаться отсчета интервала

224
ASP.NET MVC: Коллекция в модели, как заполнять?

ASP.NET MVC: Коллекция в модели, как заполнять?

Помогите разобратьсяСгенерировал crud контроллер

492
Запутался с флагами, ARM

Запутался с флагами, ARM

Доброго времени сутокЧто-то я уже мозг сломал

203