Как перегрузить оператор скобки, чтобы получить два значения [duplicate]

Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.

Пример:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Вы можно просто избежать этого, проверив, является ли переменная не нулевой:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

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

Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!

Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.

Типы ссылок (эти должны быть проверены):

  • динамический
  • объект
  • string

Типы значений (вы можете просто игнорировать эти):

  • Числовые типы
  • Интегральные типы
  • Типы с плавающей запятой
  • decimal
  • bool
  • Пользовательские структуры

43
задан Jon Seigel 10 April 2010 в 19:20
поделиться

5 ответов

Нет, вы не можете перегрузить operator[], чтобы принять несколько аргументов. Вместо этого вы можете перегрузить operator(). См. . Как создать индексный оператор для класса Matrix? из часто задаваемых вопросов C ++.

41
ответ дан jamesdlin 23 August 2018 в 17:29
поделиться

Для полноты: существует способ фактически использовать оператор скобки с несколькими аргументами, если они не являются базовыми типами данных, а именно , перегружая запятый оператор , а не оператор скобки, см. следующее сообщение о перегрузке запятой:

https://stackoverflow.com/a/18136340/5836981

Отказ от ответственности: на мой взгляд, перегрузка оператора запятой является подверженность ошибкам и делает код более неясным, и его стоит рассматривать только в более экзотических случаях. Я добавил этот ответ, потому что я получил экземпляр этого кода в некотором коде, и мне потребовалось некоторое время, чтобы понять, что ключ не был оператором [] (который не может быть перегружен несколькими аргументами), но оператором.

6
ответ дан Community 23 August 2018 в 17:29
поделиться
  • 1
    wow, я не знал, что у вас может быть несколько аргументов в скобке, перегружая operator,, который является гением / злым гением / вероятно, ужасной идеей, в большинстве случаев. – Trevor Boyd Smith 2 August 2018 в 16:47

N-мерные массивы произвольного типа и размера в C ++:

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

Я написал класс шаблона c ++ для создания n-мерного массива произвольного типа и размера. Он должен быть создан с типом массива и количеством измерений. Размер можно изменять динамически. Ниже приведена голая (лишенная) рабочая версия того, как создать многомерный массив, к которому можно получить доступ к элементам через последовательное применение оператора [] (например, массив [x] [y] [г]). Эта версия может обрабатывать только массивы размерности n> 1. Основная функция показывает, как создать в качестве примера 4-мерный массив целых чисел.

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

#include <stdio.h>
#include <stdlib.h>

template <typename T, int N>
struct array {
    array<T,N>() : data(NULL), offset((int*) malloc(sizeof(int)*N)){}
    array<T,N>(T *data, int *offset) : data(data), offset(offset){}
    array<T,N-1> operator[](int i){return array<T,N-1>(&data[i*offset[N]], offset);}
    bool resize(int *size){
        offset[N-1] = 1;
        int total_size = size[N-1];
        for(int i = N-2; i >= 0; i--){
            total_size *= size[i];
            offset[i] = offset[i+1]*size[i+1];
        }
        return (data = (T*) realloc (data, total_size*sizeof(T)));
    }
    T *data;
    int *offset;
};

template <typename T>
struct array<T,1>{
    array<T,1>(T *data, int *offset) : data(data){}
    T& operator[](int i){return data[i];}
    T *data;
};

int main () {
    array<int, 4> a;

    // create array with dimensions [1][3][3][7]
    int size[4] = { 1, 3, 3, 7 };
    a.resize(size);               

    a[0][1][2][3] = 123;

    return 0;
}

Наслаждайтесь.

2
ответ дан gospes 23 August 2018 в 17:29
поделиться
  • 1
    Это довольно хорошо, но я думаю, что это путано, что он называется array и выглядит так же, как std::array при объявлении, но имеет параметры шаблона (и семантики), которые очень сильно отличаются (например, с динамическим размером!). Подумайте о том, чтобы дать ему другое имя. Также большой ew в заголовках C, malloc, realloc и free ... подождите минуту .... у вас нет free! Вы передаете данные all . Ницца. – Lightness Races in Orbit 22 November 2014 в 23:05
  • 2
    @LightnessRacesinOrbit: Думаю, я до сих пор обязан вам деструктором со свободным :), но тогда я также буду нести ответственность за обнаружение seqfaults, вызванных любым доступом за пределами границ (например, доступ до изменения размера). Что касается заголовков C .. они занимают свое место в качестве получателей моего продолжающегося увлечения, то есть я остаюсь верным своим корням :) – gospes 24 November 2014 в 13:21
  • 3
    Затем -1 для подачи ужасно ошибочного кода и опасных советов новичку на языке. – Lightness Races in Orbit 24 November 2014 в 13:32
  • 4
    Благодарим вас за то, что вы сделали этот маленький perl доступным. +1 для дидактического примера и для умного использования рекурсивного шаблона. – Christian Pagot 22 August 2018 в 02:05

Есть хороший небольшой трюк, который вы можете сделать с равномерным синтаксисом инициализации, доступным на C ++ 11. Вместо того, чтобы напрямую принимать индекс, вы берете POD.

struct indices
{
  std::size_t i, j, k;
};

T& operator[](indices idx)
{
  return m_cells[idx.k * m_resSqr + idx.j * m_res + idx.i];
}

И затем используйте новый синтаксис:

my_array<int> arr;
// ...
arr[{1, 2, 3}] = 42;
27
ответ дан Jiří Pospíšil 23 August 2018 в 17:29
поделиться
  • 1
    Вам даже не нужно писать свою собственную структуру; вы можете просто использовать std::array или std::tuple – Justin 30 January 2018 в 20:19

Невозможно перегрузить оператор [], чтобы принять несколько аргументов, но альтернативой является использование шаблона прокси.

В двух словах: a[x][y] первое выражение (a[x] ]) будет возвращать другой тип с именем прокси-типа, который будет иметь другой operator[]. Он будет называть что-то вроде _storedReferenceToOriginalObject->At(x,y) исходного класса.

Вы не сможете сделать a[x,y], но я предполагаю, что вы все равно хотите перегрузить обычный синтаксис 2D-массива в стиле C ++.

38
ответ дан Mateen Ulhaq 23 August 2018 в 17:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: