Может ли класс иметь другого члена с таким же именем в том же пространстве имен? - PullRequest
0 голосов
/ 23 декабря 2018

Предположим, у меня есть два класса с одним и тем же именем в одном и том же пространстве имен в двух разных файлах.

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

Для функций с другим поведением я переопределю их в одном экземпляре класса.

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

Есть ли способ сделать это?Ясно, что у меня не может быть двух классов в одном и том же пространстве имен, но, возможно, я смогу переопределить пространство имен / имя класса, членом которого я хочу стать для переадресации вызовов?

Например:

//file_1.h
namespace x {
 class y {
 }
}

//file_2.h
#include "file_1.h"
namespace x {
  class y {
    // member of same class in the other file
    y memberName;
  }
}

Ответы [ 3 ]

0 голосов
/ 23 декабря 2018

Вы не можете изменить класс после того, как он был объявлен, и вы не можете объявить два разных класса с одинаковыми именами.

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

class A {
public:
  virtual void f() = 0;
};
class B : public A {
  void f() override {std::cout << "B" << std::endl;}
};
class C : public A {
  void f() override {std::cout << "C" << std::endl;}
};

int main()
{
  A *a1 = new B;
  A *a2 = new C;
  a1->f(); // B
  a2->f(); // C
  return 0;
} 

Хотя оба a1, a2 являются указателями на A, код напечатает:

B
C

Если вы не хотите этого делатьпубличная иерархия классов, вы можете использовать технику pimpl .Это позволяет скрыть реальную реализацию класса.Например:

// File: A.h
class A {
  class AImpl;
  std::unique_ptr<AImpl> m_pimpl;
public:
  explicit A();
  void f();
};

// File A.cpp
class A::AImpl {
public:
  void f() { std::cout << "A" << std::endl;};
};

A::A() : m_pimpl(new AImpl) {
}

void A::f() {
  m_pimpl->f();
}

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

0 голосов
/ 23 декабря 2018

Предположим, у меня есть два класса с одинаковыми именами в одном и том же пространстве имен в двух разных файлах.

Затем вы нарушили правило под названием thd ODR или одно правило определения.Это делает вашу программу некорректной, диагностика не требуется.

Если у вас есть класс Alice, который хочет использовать другой класс Bob, но вы хотите два разных определения того, как работает Bob,решения называются «полиморфизмом».

Полиморфизм - это способность двух или более классов заменить один.

Существует три простых формы полиморфизма.Здесь используется виртуальный интерфейс и полиморфизм времени выполнения.Есть использование шаблонов и время компиляции.Затем происходит стирание типов с помощью указателей на функции.

Самым простым является определение виртуального интерфейса.

struct IBob {
  virtual int count() const = 0;
  virtual ~IBob() {}
};
struct Alice {
  std::unique_ptr<IBob> my_bob = nullptr;
  void do_stuff() const {
    if(my_bob) std::cout << "Count is:" << my_bob->count() <<"\n";
  }
};

теперь мы можем определить две реализации IBob:

struct Bob0:IBob{
  int count() const final { return 7; }
};
struct Bob1:IBob{
  std::unique_ptr<IBob> pBob;
  int count() const final {
    if(pBob) return pBob->count()*2 +1;
    else return 1;
  }
};

теперь Bob1 имеет IBob, и он использует IBob для реализации своих собственных count.

Шаблонный путь выглядит следующим образом:

template<class Bob>
struct Alice {
  Bob my_bob;
  void do_stuff() const {
    std::cout << "Count is:" << my_bob.count() <<"\n";
  }
};

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

Решение стирания типа указателя функции вручную является более сложным.Я бы посоветовал против этого.

0 голосов
/ 23 декабря 2018

Когда вы включаете файл, это все равно, что добавлять содержимое в этот файл cpp.Это означает, что у вас будет одинаковое имя для разных классов.

Существует возможность использовать одно и то же имя с помощью typedef.

class A {
public:
    static void func() {}
};

class B {
public:
    static void func() {}
};

void funcA() {
    typedef A C;
    C::func();
}

void funcB() {
    typedef B C;
    C::func();
}

int main()
{
  funcA();
  funcB();
  return 0;
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...