在同一个名称空间中,一个类是否可以具有另一个同名成员?

时间:2018-12-23 09:11:06

标签: c++ c++11

假设我在两个不同文件的相同名称空间中有两个名称相同的类。

因此,我可以使用两个类中的每个类构造另一个对象,遵循相同的接口,但某些函数的行为有所不同。

对于行为不同的函数,我将在类的一个实例中重新定义它们。

对于功能相同的函数,我想构造另一个类的实例并转发调用。

有没有办法做到这一点?显然,我不能在同一个名称空间中拥有两个类,但是也许我可以重新定义我想成为成员的类的名称空间/类名,以便转发调用?

例如:

//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 :(得分:2)

在声明了一个类之后,您不能再对其进行修改,并且您不能声明两个具有相同名称的不同类。

您可以使用虚拟方法声明类层次结构,并使用指向基址的指针。例如:

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;
} 

尽管a1a2都是指向A的指针,但代码将打印:

B
C

如果您不想公开此类层次结构,则可以使用pimpl technique。它允许您隐藏类的实际实现。 例如:

// 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使用类层次结构,以根据内部创建的类来创建不同的行为对象。

答案 1 :(得分:2)

  

假设我在两个不同文件的相同名称空间中有两个名称相同的类。

然后您违反了称为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

手动功能指针类型的擦除解决方案更加复杂。我不建议这样做。

答案 2 :(得分:0)

包含文件时,就像将内容添加到该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;
}