Раз и навсегда разбираемся как передавать ссылки и указатели в конструкторе

Существует три варианта передачи параметра в функцию, конструктор и может еще куда:

по значению
по ссылке
по указателю

И как всегда все надо проверять на практике: разбираемся как передаются параметры в функциях, конструкторах.

Чтобы больше никогда не сомневаться какой вариант выбрать ниже приложен тестовый проект на Qt 4.8.1 msvc-2010.

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

Нюанс 1 в том, что при передаче по значению объект копируется внутрь вызываемой сущности. Но если ваш объект-параметр не изменяется в последствие (внутри вызываемой сущности) компилятор может  и не создать копию, а создать просто ссылку. Но если объект-параметр присвоится внутренней переменой и та будет изменена, то копия точно будет сделана компилятором.

Нюанс 2 : при передаче по ссылке передается только адрес объекта внутрь вызываемой сущности.

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

Ссылка и указатель почти одно и то же. Но ссылка не существует отдельно от об'екта, а указатель на об'ект может существовать без самого об'екта, то есть указывать куда-то в никуда. Поэтому ссылка более надёжна (на наш взгляд) и подсознательно мы всегда стараемся работать с ссылками.

Компилятор заставляет всегда  инициализировать ссылки (после двоеточия в конструкторе). Компилятор не даст  просто создать член класса типа ссылка.

Если посмотреть проект, приложенный внизу страницы, то не должно остаться сомнений, что можно легко использовать все три варианта передачи парметров в некую сущность (функция, конструктор класса).

В проекте сделана передача одного об'екта в тестовый  класс во всех трёх вариантах и далее идёт сравнение принятых параметров по адресам и  выведен результат.

Результат говорит о том, что ссылка и указатель указывают на один и тот же об'ект.

Когда параметр передается по значению, то создаётся копия об'екта со всеми вытекающими расходами памяти. Поэтому передавать по значению имеет смысл, когда нельзя по другому.

Статические об'екты , указатели и ссылки имеет абсолютно такой же смысл, просто они существуют в одном экземпляре. И немного по другому инициализируются, точнее в другом месте (вне методов класса, снаружи в том же cpp файле).

И надо понимать наконец, что внутри сущности, в которую передан параметр в виде указателя, ссылки или по значению можно этот параметр далее передавать транслируя синтаксически как угодно: ссылку в указатель, указатель в ссылку, об'ект в ссылку,  ссылку в об'ект, указатель в об'ект, об'ект в указатель. Как угодно и все будет работать как надо.

Отличие поведения ссылки от указателя при передаче параметра ссылки/указателя на класс есть. Например нельзя передавать ссылку на класс, у которого есть заготовки виртульных методов ( =0 , т.е. без реализации).

#ifndef TEST_CLASS_H
#define TEST_CLASS_H

#include 


#include "class1.h"
//class Cl1;

class TestClass
{
    
public:

    explicit TestClass(
            Class1 Val,
            Class1 &Ref,
            Class1 *Ptr);

    

private:


    Class1            val;

    static Class1     val_st;


    Class1        & ref;

    static Class1 & ref_st;


    Class1 * ptr;

    static Class1 * ptr_st;

};

#endif // TEST_CLASS_H





#include "test_class.h"

#include "app_def.h"

#include 

#include "class1.h"

Class1 TestClass::val_st = appDef::cl1;     // have to be
Class1 &TestClass::ref_st = appDef::cl1;    // have to be
Class1 *TestClass::ptr_st = &appDef::cl1;   // have to be

TestClass::TestClass(

        Class1 Val,
        Class1 &Ref,
        Class1 *Ptr

        )

    :

      // ----------------------------------
      // init OK but 1 from 3 variants only
      // ----------------------------------

      val(Val),  // OK
      //val(Ref),  // OK
      //val(*Ptr),  // OK


      // ----------------------------------
      // init OK but 1 from 3 variants only
      // ----------------------------------

      ref(Val),   // OK
      //ref(Ref),    // OK
      //ref(*Ptr),     // OK


      // ----------------------------------
      // init OK but 1 from 3 variants only
      // ----------------------------------

      ptr(&Val)    // OK
      //ptr(&Ref),    // OK
      //ptr(Ptr)    // OK


      // ----------------------------------
      // cannot initialize static class data via constructor
      // ----------------------------------

      //val_s(Val) // cannot initialize static class data via constructor
      //val_s(Ref) // cannot initialize static class data via constructor
      //val_s(Ptr) // cannot initialize static class data via constructor

      //ref_s(Val) // cannot initialize static class data via constructor
      //ref_s(Ref) // cannot initialize static class data via constructor
      //ref_s(Ptr) // cannot initialize static class data via constructor

      //ptr_s(Val) // cannot initialize static class data via constructor
      //ptr_s(Ref) // cannot initialize static class data via constructor
      //ptr_s(Ptr) // cannot initialize static class data via constructor

{

    val.setString("123"); //будет создана копия

    qDebug() << "val " << val.getString();
    qDebug("    val %p \n",  val);

    qDebug()<< "ref " << ref.getString() ;
    qDebug("    ref %p \n",  ref);

    qDebug()<< "ptr " << ptr->getString();
    qDebug("    ptr %p %p \n\n",  ptr , *ptr);


    qDebug() << "val_st " << val_st.getString();
    qDebug("    val_st %p \n",  val_st);

    qDebug()<< "ref_st " << ref_st.getString() ;
    qDebug("    ref_st %p \n",  ref_st);

    qDebug()<< "ptr_st " << ptr_st->getString();
    qDebug("    ptr_st %p %p \n",  ptr_st , *ptr_st);



}


#include 

#include 

#include 

#include "app_def.h"
#include "test_class.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Class1 cl2("this is easy text");

    qDebug() << "----------- EASY ------------";

    TestClass test1(
                cl2,
                cl2,
                &cl2
                );

    qDebug() << "---------- STATIC ------------";

    TestClass test2(
                appDef::cl1,
                appDef::cl1,
                &appDef::cl1
                );

    return a.exec();
}


#ifndef CLASS1_H
#define CLASS1_H

#include 

class Class1
{
public:

    explicit Class1(const QString &txt);

    QString getString();

    void setString(const QString & txt);


private:

    QString txt;
};

#endif // CLASS1_H

#include "class1.h"

Class1::Class1(const QString &Txt)
    :
    txt(Txt)
{

}

QString Class1::getString()
{
    return txt;
}

void Class1::setString(const QString & Txt)
{
    txt = Txt;
}



Файлы для скачивания