Семантика передачи ссылкой по умолчанию в [закрытом] C++

Я обновил код. Возможно, это то, что вам нужно, , но это не лучшая реализация этого приложения.

Это одностраничное приложение , и, конечно, вы можете использовать для этого jQuery, но есть гораздо лучшие решения. Лучший способ - использовать одну из фреймворков (например, Angular, Vue.js, React и т. Д.). Я настоятельно советую вам получить больше информации о фреймворках и начать их использовать.

По моему мнению, Vue.js имеет низкий порог входа, и я советую прочитать документ , но у каждой среды есть свои преимущества.

Некоторые ссылки:

var quiztitle = "Quiz";


var quiz = [{
    "question": "Q1: What colour is the sky?",
    "choices": [
      "Blue",
      "Red",
      "Pink",
      "Green"
    ],
    "correct": "Blue",

  },
  {
    "question": "Q2: What colour is mustard?",
    "choices": [
      "Blue",
      "Yellow",
      "Green",
      "Red"
    ],
    "correct": "Yellow",
  },
  {
    "question": "Q3: What colour is grass?",
    "choices": [
      "Blue",
      "Yellow",
      "Red",
      "Green"
    ],
    "correct": "Green",
  },


];


var currentquestion = 0,
  score = 0,
  submt = true,
  picked;

jQuery(document).ready(function($) {


  function htmlEncode(value) {
    return $(document.createElement('div')).text(value).html();
  }


  function addChoices(choices) {
    if (typeof choices !== "undefined" && $.type(choices) == "array") {
      $('#choice-block').empty();
      for (var i = 0; i < choices.length; i++) {
        $(document.createElement('li')).addClass('choice choice-box').attr('data-index', i).text(choices[i]).appendTo('#choice-block');
      }
    }
  }

  function nextQuestion() {
    submt = true;
    $('#submitbutton').css('display', 'none');
    $('#form1').css('display', 'none');
    $('#explanation').empty();
    $('#question').text(quiz[currentquestion]['question']);
    $('#pager').text('Question ' + Number(currentquestion + 1) + ' of ' + quiz.length);
    addChoices(quiz[currentquestion]['choices']);
    setupButtons();


  }


  function processQuestion(choice) {
    if (quiz[currentquestion]['choices'][choice] == quiz[currentquestion]['correct']) {
      $('.choice').fadeIn(700, function() {
        $('.choice').eq(choice).css({
          'background-color': '#6C0',
          'color': '#ffffff',
          'font-weight': '300',
          'font-size': '20px',
          'padding': '20px'
        });
      });
      $('#explanation').fadeIn(700, function() {
        $('#explanation').html('
Correct!
' + htmlEncode(quiz[currentquestion]['explanation'])); }); score++; } else { $('.choice').eq(choice).css({ 'background-color': '#ff0000', 'color': '#ffffff', 'font-weight': '300', 'font-size': '20px', 'padding': '20px' }); $('#explanation').fadeIn(700, function() { $('#explanation').html('
Incorrect.
' + htmlEncode(quiz[currentquestion]['explanation'])); }); } currentquestion++; $('#submitbutton').fadeIn(700, function() { $('#submitbutton').html('NEXT QUESTION').on('click', function() { if (currentquestion == quiz.length) { endQuiz(); } else { $(this).text('NEXT QUESTION').css({ }).off('click'); nextQuestion(); } }); $('#submitbutton').show(); }); } function setupButtons() { $('.choice').fadeIn(700, function() { $('.choice').on('mouseover', function() { $(this).css({ 'background-color': '#f1cb00', 'color': '#005596', 'font-weight': '300', 'font-size': '20px', 'padding': '20px' }); }); }); $('.choice').fadeIn(700, function() { $('.choice').on('mouseout', function() { $(this).css({ 'background-color': '#e1e1e1', 'color': '#005596', 'font-weight': '300', 'font-size': '20px', 'padding': '20px' }); }); }) $('.choice').fadeIn(700, function() { $('.choice').on('click', function() { if (submt) { submt = false; picked = $(this).attr('data-index'); $('.choice').removeAttr('style').off('mouseout mouseover'); $(this).css({ }); $('.choice').css({ 'cursor': 'default' }); processQuestion(picked); $('#submitbutton').css({ 'padding': '20px' }); } }); }) } function endQuiz() { $('#explanation').empty(); $('#question').empty(); $('.pager').hide(); $('#choice-block').empty(); $('#submitbutton').remove(); /** * Added by Max */ const percents = Math.round(score / quiz.length * 100); let $link = $(document.createElement('a')) .css({ 'line-height': '20px', 'text-align': 'center' }); const $percents = $(document.createElement('h2')) .css({ 'line-height': '20px', 'text-align': 'center' }) .text(percents + '%'); if (percents >= 70) { $link.text('Click here'); $link.attr('href', 'https://google.com'); } else { $link.text('Click here to repeat test'); $link.attr('href', '#0') $link.on('click', ($event) => { $event.preventDefault(); clearContent(); init(); }); } $('#question').append($percents); $('#question').append($link); /** * End Added by Max */ $('#form1').show(); } // Added by Max function clearContent () { currentquestion = 0; score = 0; submt = true; picked = undefined; $('#frame').empty(); } function init() { //add title if (typeof quiztitle !== "undefined" && $.type(quiztitle) === "string") { $(document.createElement('header')).text(quiztitle).appendTo('#frame'); } else { $(document.createElement('header')).text("Quiz").appendTo('#frame'); } //add pager and questions if (typeof quiz !== "undefined" && $.type(quiz) === "array") { //add pager $(document.createElement('p')).addClass('pager').attr('id', 'pager').text('Question 1 of ' + quiz.length).appendTo('#frame'); //add first question $(document.createElement('h2')).addClass('question').attr('id', 'question').text(quiz[0]['question']).appendTo('#frame'); $(document.createElement('p')).addClass('explanation').attr('id', 'explanation').html(' ').appendTo('#frame'); //questions holder $(document.createElement('ul')).attr('id', 'choice-block').appendTo('#frame').css({ 'padding-top': '20px' }) //add choices addChoices(quiz[0]['choices']); //add submit button $(document.createElement('div')).addClass('choice-box').attr('id', 'submitbutton').text('NEXT QUESTION').css({ }).appendTo('#frame'); setupButtons(); $('#submitbutton').hide(); $('#form1').hide(); } } init(); });
header {
   background: #005596;
   color: #ffffff;
   padding: 20px;
   overflow: auto;
   font-size: 21pt;
   margin-bottom: 40px;
   -webkit-border-radius: 5px;
   -moz-border-radius: 5px;
   border-radius: 5px;
 }

 .correct {
   color: #6C0;
   font-family: Tahoma, sans-serif;
   font-weight: 500;
   font-size: 26pt;
   text-align: left;
   padding: 30px 0 10px 30px;
 }

 .wrong {
   color: #ff0000;
   font-family: Tahoma, sans-serif;
   font-weight: 500;
   font-size: 26pt;
   text-align: left;
   padding: 30px 0 10px 30px;
 }

 ol,
 ul {
   list-style: none;
   list-style-position: inside;
 }

 p.pager {
   margin: 5px 0 5px;
   font-weight: 500;
   font-size: 2em;
   line-height: 2em;
   color: #999;
 }

 #choice-block {
   display: block;
   list-style: none;
   margin: -20px 15px 0 -15px;
   padding: 0;
 }

 #submitbutton {
   -webkit-appearance: none;
   -webkit-border-radius: 5px;
   -moz-border-radius: 5px;
   border-radius: 5px;
   border: none;
   appearance: none;
   background: #005596;
   display: inline-block;
   text-decoration: none;
   padding: 12px;
   font-family: Tahoma, sans-serif;
   font-size: 14pt;
   color: #FFF;
   font-weight: bold;
   margin-top: 20px;
 }

 #submitbutton:hover {
   background-color: #f1cb00;
   text-decoration: none;
   -webkit-transition: 0.3s;
   -moz-transition: 0.3s;
   -ms-transition: 0.3s;
   -o-transition: 0.3s;
   transition: 0.3s;
 }

 #Submit {
   -webkit-appearance: none;
   -webkit-border-radius: 5px;
   -moz-border-radius: 5px;
   border-radius: 5px;
   border: none;
   appearance: none;
   background: #005596;
   display: inline-block;
   text-decoration: none;
   padding: 20px;
   font-family: Tahoma, sans-serif;
   font-size: 14pt;
   color: #FFF;
   font-weight: bold;
   margin-top: 20px;
 }

 #Submit:hover {
   background-color: #f1cb00;
   text-decoration: none;
   -webkit-transition: 0.3s;
   -moz-transition: 0.3s;
   -ms-transition: 0.3s;
   -o-transition: 0.3s;
   transition: 0.3s;
 }

 .choice-box {
   display: block;
   text-align: left;
   margin: 8px auto;
   color: #005596;
   font-weight: 300;
   font-size: 20px;
   padding: 20px;
   cursor: pointer;
   -webkit-border-radius: 5px;
   -moz-border-radius: 5px;
   border-radius: 5px;
   background: #e1e1e1;
 }

 @media only screen and (max-width: 900px) {
   .correct {
     padding: 20px 0 0 0;
   }
   .wrong {
     padding: 20px 0 0 0;
   }
 }

7
задан Coding Mash 7 September 2012 в 19:55
поделиться

9 ответов

Я предполагаю, что Вы упускаете суть C++ и семантику C++. Вы пропустили факт, C++ корректен мимоходом (почти) все значением, потому что это - способ, которым это сделано в C. Всегда. Но не только в C, поскольку я покажу Вам ниже...

Семантика параметров на C

В C все передается значением. "примитивы" и "ПЕРЕХОДНЫЕ ПРИСТАВКИ" передаются путем копирования их значения. Измените их в своей функции, и оригинал не будет изменен. Однако, стоимость копирования некоторых ПЕРЕХОДНЫХ ПРИСТАВОК могла быть нетривиальной.

При использовании нотации указателя (*), Вы не являетесь передающими ссылкой. Вы передаете копию адреса. Который является более или менее тем же, с, но одним тонким различием:

typedef struct { int value ; } P ;

/* p is a pointer to P */
void doSomethingElse(P * p)
{
   p->value = 32 ;
   p = malloc(sizeof(P)) ; /* Don't bother with the leak */
   p->value = 45 ;
}

void doSomething()
{
   P * p = malloc(sizeof(P)) ;
   p->value = 25 ;

   doSomethingElse(p) ;

     int i = p->value ;
   /* Value of p ? 25 ? 32 ? 42 ? */
}

Окончательное значение p-> значение равняется 32. Поскольку p был передан путем копирования значения адреса. Таким образом, оригинал p не был изменен (и новый был пропущен).

Семантика параметров на Java и C sharp

Это может быть удивительно для некоторых, но в Java, все копируется значением, также. Пример C выше дал бы точно те же результаты в Java. Это почти, что Вы хотите, но Вы не смогли бы передать примитивный "ссылкой/указателем" так же легко как в C.

В C# они добавили "касательно" ключевого слова. Это работает более или менее как ссылка в C++. Точка на C#, необходимо упомянуть это и на объявлении функции, и на каждом вызове. Я предполагаю, что это не то, что Вы хотите, снова.

Семантика параметров на C++

В C++ почти все передается путем копирования значения. То, когда Вы используете только тип символа, Вы копируете символ (как он сделано в C). Поэтому, когда Вы используете *, Вы передаете копию адреса символа.

Но когда Вы используете и, затем предполагаете передачу реального объекта (быть этим структура, интервал, указатель, безотносительно): ссылка.

Легко перепутать его как syntaxic сахар (т.е. негласно, это работает как указатель, и сгенерированный код является тем же, используемым для указателя). Но...

Истина - то, что ссылка является больше, чем syntaxic сахар.

  • В отличие от указателей, это разрешает управлять объектом как будто на стеке.
  • Указатели нестроки, когда associatied с ключевым словом константы, это авторизовывает неявное продвижение от одного типа до другого (через конструкторов, главным образом).
  • В отличие от указателей, символ, как предполагается, не является ПУСТЫМ/НЕДОПУСТИМЫМ.
  • В отличие от "копией", Вы не проводите бесполезное время, копируя объект
  • В отличие от "копией", можно использовать его в качестве параметр
  • В отличие от "копией", можно использовать полный спектр ООП в C++ (т.е. Вы передаете полный объект функции, ожидая интерфейс).

Так, ссылки имеет лучший из обоих миров.

Давайте посмотрим пример C, но с вариацией C++ на функцию doSomethingElse:

struct P { int value ; } ;

// p is a reference to a pointer to P
void doSomethingElse(P * & p)
{
   p->value = 32 ;
   p = (P *) malloc(sizeof(P)) ; // Don't bother with the leak
   p->value = 45 ;
}

void doSomething()
{
   P * p = (P *) malloc(sizeof(P)) ;
   p->value = 25 ;

   doSomethingElse(p) ;

     int i = p->value ;
   // Value of p ? 25 ? 32 ? 42 ?
}

Результат равняется 42, и старый p был пропущен, заменен новым p. Поскольку, в отличие от кода C, мы не передаем копию указателя, но ссылку на указатель, то есть, сам указатель.

При работе с C++ вышеупомянутым примером должен быть ясный cristal. Если это не, то Вы пропускаете что-то.

Заключение

C++ является pass-by-copy/value, потому что это - способ, которым все работает, быть им в C, в C# или в Java (даже в JavaScript... :-p...). И как C#, C++ имеет ссылочный оператор / ключевое слово в качестве награды.

Теперь, насколько я понимаю это, Вы, возможно, делаете то, что я называю half-jockingly C +, то есть, C с некоторыми ограничил функции C++.

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

Как сказано в другом сообщении, необходимо изменить мышление от разработки C (что) к разработке C++, или необходимо, возможно, переместиться в другой язык. Но не продолжайте программировать путь C с функциями C++, потому что путем сознательного игнорирования/запутывания питания идиом Вы используете, Вы произведете субоптимальный код.

Примечание: И не передавайте копией ничто больше, чем примитивы. Вы будете кастрировать свою функцию от ее способности OO, и в C++, это не то, что Вы хотите.

Править

Вопрос был несколько изменен (см. https://stackoverflow.com/revisions/146271/list). Я позволяю своему исходному ответу и отвечаю на новые вопросы ниже.

Что Вы думаете о семантике передачи ссылкой по умолчанию на C++? Как Вы сказал, это повредит совместимость, и у Вас будет другая передача - для примитивов (т.е. встроенные типы, которые были бы все еще переданы копией), и структуры/объекты (который будет передан как ссылки). Необходимо было бы добавить другой оператор для значения "передачи значением" (экстерн "C" довольно ужасен и уже используемый для чего-то еще очень отличающегося). Нет, мне действительно нравится способ, которым это сделано сегодня в C++.

[...] ссылочный оператор кажется мне способом получить переменный адрес, это - способ, которым я использовал для получения указателей. Я имею в виду, это - тот же оператор, но с различным, семантическим на различных контекстах, разве который не чувствует немного неправильное при Вас также? Да и нет. Оператор>> изменил свое семантическое при использовании с потоками C++, также. Затем можно использовать оператор + = для замены strcat. Я предполагаю оператор и привык, потому что его значение как "противоположность указателя", и потому что они не хотели использовать еще один символ (ASCII ограничен, и оператор объема:: а также указатель-> показывает, что немного других символов применимы). Но теперь, если и беспокойства Вы, && действительно расстроите Вас, поскольку они добавили унарный && в C++ 0x (своего рода суперссылка...). Я должен все же переварить его сам...

15
ответ дан 6 December 2019 в 05:56
поделиться

Я больше не злоупотреблял бы ссылками путем создания каждого (неквалифицированного) параметра ссылкой.

Главная причина ссылки были добавлены к C++, состояла в том, чтобы поддерживать перегрузку оператора; если Вы хотите семантику "передачи ссылкой", C имел совершенно разумный способ сделать ее: указатели.

Используя указатели ясно дает понять Ваше намерение изменить значение резкого объекта, и возможно видеть это, просто смотря на вызов функции, Вы не должны смотреть на объявление функции, чтобы видеть, использует ли это ссылку.

Кроме того, посмотрите

Я действительно хочу изменить аргумент, я должен использовать указатель, или я должен использовать ссылку? Я не знаю сильную логическую причину. При передаче ''не объект'' (например, нулевой указатель) приемлем, использование указателя имеет смысл. Мой персональный стиль должен использовать указатель, когда я хочу изменить объект, потому что в некоторых контекстах, который помогает определить это, модификация возможна.

от того же FAQ.

2
ответ дан 6 December 2019 в 05:56
поделиться

Параметр компилятора, который полностью изменяет значение раздела кода, походит на действительно плохую идею мне. Или получите использование к синтаксису C++ или найдите другой язык.

10
ответ дан 6 December 2019 в 05:56
поделиться

Да, я имею мнение, что это - довольно запутывающая перегрузка.

Это - то, что Microsoft должна заявить о ситуации:

Не путайте ссылочные объявления с использованием операции вычисления адреса. Когда и идентификатор предшествуется типом, таким как интервал или символ, затем идентификатор объявляется как ссылка на тип. Когда и идентификатор не предшествуется типом, использование является использованием операции вычисления адреса.

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

1
ответ дан 6 December 2019 в 05:56
поделиться

Лучший совет состоит в том, чтобы сделать привычку к размышлению о том, что Вы действительно хотите произойти. Передача ссылкой хороша, когда у Вас нет конструктора копии (или не хотят использовать его), и это более дешево для больших объектов. Однако затем мутации к параметру чувствуют вне класса. Вы могли вместо этого пройти мимо const ссылка - затем нет никаких мутаций, но Вы не можете сделать локальные модификации. Константа передачи значением для дешевых объектов, которые должны быть только для чтения в функции и неконстанте передачи значением, когда Вы хотите копию, к которой можно сделать локальные модификации.

Каждая перестановка (by-value/by-reference и const/non-const) имеет важные различия, которые определенно не эквивалентны.

1
ответ дан 6 December 2019 в 05:56
поделиться

Когда Вы передаете значением, Вы копируете данные в стек. Если у Вас есть оператор = определенный для структуры или класса, что Вы передаете его, это выполняется. Нет никакой директивы компилятора, о которой я знаю, который смыл бы вздор неявного беспорядка языка, который по сути вызовет предложенное изменение.

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

Полностью корректная константой кодовая база идет еще больше, добавляя константу в конец прототипов. Рассмотрите:

void Foo::PrintStats( void ) const {
   /* Cannot modify Foo member variables */
}

void Foo::ChangeStats( void ) {
   /* Can modify foo member variables */
}

Если необходимо было передать объект Foo в функции, снабженной префиксом константу, Вы можете назвать PrintStats (). Компилятор был бы ошибка на вызове к ChangeStats ().

void ManipulateFoo( const Foo &foo )
{
    foo.PrintStats();  // Works
    foo.ChangeStats(); // Oops; compile error
}
1
ответ дан 6 December 2019 в 05:56
поделиться

Я честно думаю, что эта целая передача значением/передачей ссылочной идеей в C++ вводит в заблуждение. Все - передача значением. У Вас есть три случая:

  1. Куда Вы передаете локальную копию переменной

    void myFunct(int cantChangeMyValue)
    
  2. Куда Вы передаете локальную копию указателя на переменную

    void myFunct(int* cantChangeMyAddress) {
        *cantChangeMyAddress = 10;
    }
    
  3. Куда Вы передаете 'ссылку', но через волшебство компилятора это - так же, как если бы Вы передали указатель и просто разыменовали его каждый раз.

    void myFunct(int & hereBeMagic) {
        hereBeMagic = 10; // same as 2, without the dereference
    }
    

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

То, что Вы предлагаете, не позволило бы программисту делать номер 1. Я лично думаю, что это было бы плохой идеей устранить ту опцию. Один майор плюс C/C++ имеет, имеют мелкомодульное управление памятью. Создание всего передать ссылкой просто пытается сделать C++ больше как Java.

1
ответ дан 6 December 2019 в 05:56
поделиться

существует что-то не ясное. когда Вы говорите:

интервал b (b &param);

что Вы предназначали для второго 'b'? Вы забывали представлять тип? Вы забывали писать по-другому относительно первого 'b'? не делайте Вы думаете, что это ясно записать что-то как:

class B{/*something...*/};
int b(B& param);

С тех пор теперь, я предполагаю, что Вы имеете в виду то, что я пишу.

Теперь, Ваш вопрос, "не делают Вы думаете, будет лучше, что компилятор рассмотрит каждую передачу значением не-POD как pass-ref?". Первая проблема состоит в том, что это будет, нарушил Ваши условия контракта. Я предполагаю, что Вы имеете в виду pass-by-CONST-reference, и не только ссылкой.

Ваш вопрос теперь уменьшается до этого: "Вы знаете, существует ли некоторая директива компиляторов, которая может оптимизировать вызов функции значением?"

Ответ теперь, "Я не знаю".

0
ответ дан 6 December 2019 в 05:56
поделиться

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

Это быстро выходит из-под контроля для отслеживания всех вызовов конструкторов копии, все разыменовывание, перегруженное и так далее.

0
ответ дан 6 December 2019 в 05:56
поделиться
Другие вопросы по тегам:

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