Основы ООП C ++ (назначение объекта в качестве члена) - PullRequest
2 голосов
/ 12 сентября 2010

Я разработчик PHP, пытаюсь написать немного C ++.

У меня проблемы с назначением объекта как свойства другого объекта. В PHP я бы написал так:

class A {
    public $b;
}
class B {

}

$a = new A;
$a->b = new B;

Как мне это сделать в C ++? Я получил это до сих пор:

class A {
    B b;
public:
    void setB(&B);
};
class B {

};

void A::setB(B &b)
{
    this->b = b;
};

A * a = new A();
B * b = new B();
a->setB(b);

Что я делаю не так?

Ответы [ 4 ]

6 голосов
/ 12 сентября 2010

Просто сделайте это:

class B 
{
};

class A
{
    B b;
};


int main()
{
   A  anA;  // creates an A. With an internal member of type B called b.

   // If you want a pointer (ie using new.
   // Then put it in a smart pointer.
   std::auto_ptr<A>  aPtr = new A();
}

На самом деле вам не нужно создавать B отдельно. B b является частью класса и создается (используя конструктор по умолчанию) автоматически при создании объекта A. Создание двух отдельных объектов и последующее их объединение - плохая идея.

Если вы хотите передать некоторые параметры объекту B при его создании. Это легко сделать, создав конструктор для A, который вызывает конструктор B:

class B
{
    public:
      B(std::string const& data)    // The B type takes a string as it is constructed.
        :myData(data)               // Store the input data in a member variable.
      {}
    private:
      std::string myData;
};
class A
{
    public:
      A(std::string const& bData)   // parameter passed to A constructor
          :b(bData);                // Forward this parameter to `b` constructor (see above)
      {}
    private:
      B  b;
};

int main()
{
    A  a("Hi there");  // "Hi there" now stored in a.b.myData
}
2 голосов
/ 12 сентября 2010
  1. Вместо &B вы имеете в виду B&.

    class A {
        B b;
    public:
        void setB(B&); //<--
    };
    
  2. Указатель не может быть явно разыменован. Так что a->setB(b) не скомпилируется. Вам нужно написать a->setB(*b).

  3. Вам не нужно new, чтобы построить объект. Например, это работает:

    A a;
    B b;
    a.setB(b);
    
  4. Не используйте идиомы из других языков непосредственно в C ++. Например, сеттеры и геттеры нужны редко. Фактически, ваш класс A может быть простой структурой.

1 голос
/ 12 сентября 2010

Несколько изменений приведут к компиляции:
1. класс B должен быть объявлен до A, чтобы его можно было использовать в классе A
2. Объявление setB (& B) нуждается в незначительном изменении для setB (B &)

class B {
};

class A {
    B b;
public:
    void setB(B&);
};
void A::setB(B &b)
{
    this->b = b;
};

int main ()
{   
A * a = new A();
B * b = new B();
a->setB(*b);
}   

Чтобы сделать его более эффективным, рассмотрите добавление следующего конструктора, который принимает B в качестве аргумента и инициализирует переменную-член 'b'. При этом будет использоваться конструктор копирования в переменной-члене 'b' вместо конструктора по умолчанию, а затем оператора присваивания.

A(B& b_) : b(b_) 
{
}
0 голосов
/ 13 сентября 2010

С этим кодом много чего не так:

  • Как отмечает KennyTM, амперсанд находится не в том месте.
  • Вы передаете B * функции, которая принимает B &, они не одинаковы в C ++
  • Дизайн, показанный в вашем фрагменте php, выглядит неправильно.Хотя то, что вы делаете, это то, что вы, возможно, захотите делать время от времени, вы, скорее всего, захотите использовать вместо этого конструктор, C ++ и PHP.
  • Вы помещаете код непосредственно в файл, это не разрешено в C ++, вместо этого поместите его в основную функцию
  • управление памятью: вы используете new без delete (или класс умного указателя)
  • Вы используете класс B в классе A, в то время как класс A не знает о классе B (он будет определен позже) - вы должны поставить класс B поверх(или, возможно, используйте предварительное объявление)

Ниже показано несколько способов правильной работы вашего кода.

include <memory>
using std::auto_ptr;


class B
{
}

class A
{
public:
    A();
    SetB(B& b);

private:
    B b1;    // a B made in the constructor
    B b2;    // a COPY of the original B you make
}

A::A()
   : b1(/*whatever you want to pass to B's constructor*/)
{
}

A::SetB(B& b)
{
    b2 = b;
}

int main(int agrc, char** argv)
{
    A firstA();
    B firstB();

    firstA.SetB(firstB);

    A* secondA = new A();
    B* secondB = new B();

    secondA->SetB(*secondB);

    auto_ptr<A> thirdA(new A());
    auto_ptr<B> thirdB(new B());

    thirdA->SetB(*thirdB);

    // whatever other code

    delete secondA;
    delete secondB;
}

Обратите внимание, что id вы вызываете SetB только один раз (и естьнет проблем с циклическими зависимостями между различными объектами, которые вы создаете), но вам do нужна гибкость построения B вне класса, вместо этого вы можете сделать параметр конструктора.

Также обратите внимание, что вы делаете копию B, которую вы создаете в main - если вы хотите использовать пришедшую копию в классе (как вы это делаете в PHP), вы должны использовать ссылку на член (в этом случае вам нужно будет установитьчто это гВ конструкторе это невозможно, вы не можете сделать это в функции SetB.

Затем обратите внимание, что существуют серьезные проблемы с подходом secondA, secondB, и поэтому он не рекомендуется (выше ничего не будет работать неправильнотем не менее, легко получить код, который пропускает память таким образом (и трудно выяснить, где утечка), и вдобавок к этому, когда вы хотите использовать исключения, вам понадобится безопасный код для исключения, который недостижим при использовании обычногостарые указатели.

Наконец, обратите внимание, что вы смешиваете и сопоставляете здесь.Например, нет никаких проблем с использованием firstA и третьего B вместе.

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