6.26 using声明与继承

using声明有时候被用于调整对基类成员的访问。例如:

  1. class Foo {
  2. public:
  3. int blah(int x);
  4. };
  5. class Bar {
  6. public:
  7. double blah(double x);
  8. };
  9. class FooBar : public Foo, public Bar {
  10. public:
  11. using Foo::blah;
  12. using Bar::blah;
  13. char *blah(const char *x);
  14. };

在这个例子中,using声明在派生类中引入了不同版本重载的blah()方法。例如:

  1. FooBar *f;
  2. f->blah(3); // Ok. Invokes Foo::blah(int)
  3. f->blah(3.5); // Ok. Invokes Bar::blah(double)
  4. f->blah("hello"); // Ok. Invokes FooBar::blah(const char *);

当这样的代码被包装时,SWIG也会模拟类似的功能。例如,如果你在Python中包装这段代码时,工作方式和你期望的方式一样:

  1. >>> import example
  2. >>> f = example.FooBar()
  3. >>> f.blah(3)
  4. >>> f.blah(3.5)
  5. >>> f.blah("hello")

using声明还能用于改变访问方式。例如:

  1. class Foo {
  2. protected:
  3. int x;
  4. int blah(int x);
  5. };
  6. class Bar : public Foo {
  7. public:
  8. using Foo::x; // Make x public
  9. using Foo::blah; // Make blah public
  10. };

SWIG也支持这样的工作方式——包装后也能正常工作。

using声明通过上面的方式使用时,基类中的声明被拷贝至派生类,然后正常包装。当拷贝时,这些声明依然保持使用%rename%ignore%feature指令关联的任何属性。因此,如果方法在基类中被忽略,即使使用了using声明也还是被忽略。

由于using声明不提供对导入声明的细粒度控制,对这些声明的管理可能很困难,要使用很多SWIG自定义特性。如果你不能让using正确的工作,你总能像下面这样做:

  1. class FooBar : public Foo, public Bar {
  2. public:
  3. #ifndef SWIG
  4. using Foo::blah;
  5. using Bar::blah;
  6. #else
  7. int blah(int x); // explicitly tell SWIG about other declarations
  8. double blah(double x);
  9. #endif
  10. char *blah(const char *x);
  11. };

注意:

  • 如果派生类重新定义了基类的方法,using声明也不会导致冲突。例如:
  1. class Foo {
  2. public:
  3. int blah(int );
  4. double blah(double);
  5. };
  6. class Bar : public Foo {
  7. public:
  8. using Foo::blah; // Only imports blah(double);
  9. int blah(int);
  10. };
  • 消除重载的歧义可以通过使用using导入声明来实现。例如:
  1. %rename(blah_long) Foo::blah(long);
  2. class Foo {
  3. public:
  4. int blah(int);
  5. long blah(long); // Renamed to blah_long
  6. };
  7. class Bar : public Foo {
  8. public:
  9. using Foo::blah; // Only imports blah(int)
  10. double blah(double x);
  11. };