C ++ указатели на экземпляры классов - PullRequest
4 голосов
/ 16 февраля 2010

У меня (для программистов на C ++ лучше меня) простая проблема с классами и указателями. Я думал о публикации примера кода, описывающего мою проблему, но мне было проще просто объяснить это словами.

Предположим, у меня есть три класса:

  • Класс A: Основной класс - он содержит экземпляры B и C.
  • Класс B: Этот класс содержит метод, который выводит некоторую строку, называем ее Greet().
  • Класс C: У этого метода тоже есть метод, но этот метод должен вызывать Greet() в случае B, который находится в классе A. Давайте назовем это DoSomethingWithB()

Итак, программа запускается, в основной функции я создаю экземпляр A. A снова создает экземпляры B и C. Затем А звонит C.DoSomethingWithB();.

И тут начинается моя проблема: я не могу получить доступ к B изнутри C.

Очевидно, мне нужно будет передать указатель на B в функцию DoSomethingWithB(), чтобы я мог вызвать B.Greet() изнутри C

Длинное объяснение, короткий вопрос: Как мне это сделать?

Пример кода входящего:

#include <iostream>
using namespace std;

class B
{
public:
    void Greet( )
    {
        cout<<"Hello Pointer!"<<endl;
    }
};

class C
{
public:
    void DoSomethingWithB( )
    {
        // ... b.Greet( ); Won't work obviously
    }
};

class A
{
public:
 B b; // Not caring about visibility or bad class/variable names here
 C c;
 void StartTest( )
 {
      c.DoSomethingWithB( );
 }
};

int main( )
{
    A mainInstance;
    mainInstance.StartTest();
}

Ответы [ 6 ]

8 голосов
/ 16 февраля 2010

Не могли бы вы просто передать указатель или ссылку на B объект?

class C 
{ 
public: 
    void DoSomethingWithB( B& b) 
    { 
        b.Greet( ); // will work fine 
    } 
}; 

class A 
{ 
public: 
 B b; // Not caring about visibility or bad class/variable names here 
 C c; 
 void StartTest( ) 
 { 
      c.DoSomethingWithB( b); 
 } 
};

Если функция DoSomethingWithB() не будет изменять переданный в B экземпляр, вы должны пометить ссылку const, чтобы ее можно было вызвать с помощью объекта const B (например, если владеющий A объект оказывается const):

void DoSomethingWithB( B const& b);

У вас есть несколько вариантов передачи объекта B в функцию:

  • в качестве ссылки (void DoSomethingWithB( B& b)), которая позволит функции изменять переданный объект. Изменения будут отражены в переданном объекте.

  • как ссылка const (void DoSomethingWithB( B const& b)), которая не позволяет функции изменять переданный объект (если только не отброшена константность), что может привести к неопределенному поведению, если оно выполняется на объекте верно const)

  • в качестве указателя или const указатель на B объект (void DoSomethingWithB( B* b) или void DoSomethingWithB( B const* pb)). Они имеют схожую производительность с передачей по ссылке, но функции может быть передан NULL-указатель, с которым необходимо обращаться должным образом (не разыменовывая его в этом случае). Кроме того, вызов функции должен немного измениться, чтобы передать адрес объекта B:

    c.DoSomethingWithB( &b);
    
  • в качестве параметра передачи по значению (void DoSomethingWithB( B b)). Это имеет различие в том, что функция может делать что угодно с переданным объектом theo, и это не повлияет на первоначально переданный объект, так как функция имеет дело с копией. Недостатком является то, что передача параметра приводит к созданию копии, которая может быть дорогой. Вы также можете передать значение const, но мало что порекомендовать при передаче ссылки const.

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

3 голосов
/ 16 февраля 2010

Измените функции на следующие:

void DoSomethingWithB(B& b)
{
    b.Greet();
}

... и в А ...

c.DoSomethingWithB(b);
2 голосов
/ 16 февраля 2010

Вы можете сделать это так, как вы сказали - передать указатель (или ссылку) на B в DoSomethingWithB():

class C
{
public:
    void DoSomethingWithB(B & bInstance)
    {
        bInstance.Greet( ); // should work fine!
    }
};

Тогда вы будете вызывать это так:

class A
{
public:
    B b; // Not caring about visibility or bad class/variable names here
    C c;
    void StartTest( )
    {
        c.DoSomethingWithB( b );
    }
};

Я бы предложил использовать здесь ссылочный подход, а не указатель, поскольку:

  1. Ваш объект является автоматическим членом класса, а
  2. Передача нулевого объекта B в функцию в этом случае не имеет смысла.
0 голосов
/ 16 февраля 2010

Я не могу получить доступ к B изнутри C

Вместо использования методов вызова C в B, почему бы не сделать так, чтобы C возвращал информацию вызывающей стороне, чтобы он мог выполнить операцию?

Когда я их ударил, я обнаружил, что у меня плохо организованы занятия. Обычно, если я переосмысливаю их, трудности исчезают с новой организацией.

0 голосов
/ 16 февраля 2010

В классе C объявите метод DoSomethingWithB() следующим образом:

void DoSomethingWithB( B* b )
{
   b->Greet();
}

А в классе A вызовите его так:

void StartTest()
{
    c.DoSomethingWithB( &b );
}

Поскольку вы упомянули указатели,ответил с помощью указателей.Однако в C ++ вы должны стараться использовать ссылки const всякий раз, когда можете.Это, конечно, потребует небольшого изменения в существующем коде:

void DoSomethingWithB( const B& b )
{
   b.Greet();
}

// and

void StartTest()
{
    c.DoSomethingWithB( b );
}
0 голосов
/ 16 февраля 2010
class C 
{ 
public: 
    C (B & b) : b(b) {}
    void DoSomethingWithB( ) 
    { 
        // ... b.Greet( ); Use b;
    } 
private:
    B & b;
}; 

class A 
{ 
public: 
 B b; // Declare b before c! 
 C c; 
 A() : c (b) {}
 void StartTest( ) 
 { 
      c.DoSomethingWithB( ); 
 } 
}; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...