将方法添加到其他文件中的现有 C++ 类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18804402/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Add a method to existing C++ class in other file
提问by acegs
Is it possible in C++ to extend a class(add a method) in a different source file without editing the original source file where the class is written?
在 C++ 中是否可以在不同的源文件中扩展类(添加方法)而不编辑编写类的原始源文件?
In obj-c it is possible by writing another @interface AbcClass (ExtCategory) ... @end
在 obj-c 中,可以通过编写另一个 @interface AbcClass (ExtCategory) ... @end
I got compile-time error(s) when I tried something like this:
当我尝试这样的事情时,我遇到了编译时错误:
//Abc.h
class Abc { //This class is from a 3rd party library....
// ...I don't want to edit its source file.
void methodOne();
void methodTwo();
}
//Abc+Ext.h
class Abc { // ERROR: Redefinition of 'Abc'
void methodAdded();
}
How can I add a method without creating a derived class? My target is to retain the 'Abc' name and add methods to it. A specific class in a 3rd party library that I used lacks some methods and I want to add those methods but I am keeping the source file unedited.
如何在不创建派生类的情况下添加方法?我的目标是保留“Abc”名称并为其添加方法。我使用的第 3 方库中的特定类缺少一些方法,我想添加这些方法,但我保持源文件未编辑。
Is there a way to do this? I am new in writing C++ codes. I am familiar with some of its syntax but don't know much.
有没有办法做到这一点?我是编写 C++ 代码的新手。我熟悉它的一些语法,但不太了解。
回答by Manoj Awasthi
No. This kind of class extension is not possible in C++
. But you can inherit a class from the original source file and add new functions in your source file.
不。这种类扩展在C++
. 但是您可以从原始源文件继承一个类并在源文件中添加新函数。
//Abc.h
class Abc {
void methodOne();
void methodTwo();
};
//Abc+Ext.h
class AbcExt : public Abc {
void methodAdded();
};
You can then call methods as following:
然后,您可以按如下方式调用方法:
std::unique_ptr<AbcExt> obj = std::make_unique<AbcExt>();
obj->methodOne(); // by the virtue of base class
obj->methodAdded(); // by the virtue of derived class
回答by Darhuuk
There's a way to actually do this, but it requires the compiler to support #include_next
. GCC has this, no idea about other compilers. It also needs to support at least C++11.
有一种方法可以真正做到这一点,但它需要编译器支持#include_next
. GCC 有这个,不知道其他编译器。它还需要至少支持 C++11。
I wouldn't exactly call this trick beautiful, but it does the job.
我不会完全称这个技巧很漂亮,但它确实有效。
Ensure your include path has the the directory where the "extension" file resides before the directory where the original code resides (i.e. if the original Abc.hpp
is in src
, then move it to src/some_dir
). So in this case your include dirs would be -Isrc -Isrc/some_dir
.
确保您的包含路径在原始代码所在的目录之前具有“扩展”文件所在的目录(即,如果原始代码Abc.hpp
在 中src
,则将其移至src/some_dir
)。因此,在这种情况下,您的包含目录将是-Isrc -Isrc/some_dir
.
Your "extension" code should be in a file with the exact same name as the original code. So for this example that's Abc.hpp
.
您的“扩展”代码应位于与原始代码同名的文件中。所以对于这个例子,就是Abc.hpp
.
Here's the extension file's content:
这是扩展文件的内容:
#ifndef ABC_EXT_HPP_
#define ABC_EXT_HPP_
#include <utility>
namespace evil {
// Search the include path for the original file.
#include_next "Abc.hpp"
}
class Abc : public evil::Abc {
public:
/*
// Inherit all constructors from base class. Requires GCC >=4.8.
using evil::Abc::Abc;
*/
/* Use the solution below if your compiler supports C++11, but not
* inheriting constructors.
*/
template <class... Args>
Abc (Args... args) : evil::ABC(std::forward<Args...>(args...)) { }
~Abc () { }
void methodAdded () { /* Do some magic. */ }
};
#endif // ABC_EXT_HPP_
There's things missing in the example such as the assignment operator not being "forwarded" to the base class. You can use the same trick as used for the constructor to do that. There might be other things missing, but this should give you a starting point which works well enough for "simple" classes.
示例中缺少一些内容,例如未将赋值运算符“转发”到基类。您可以使用与构造函数相同的技巧来做到这一点。可能还缺少其他东西,但这应该为您提供一个起点,该起点对于“简单”类来说足够好。
One thing I dislike is the creation of the "evil" namespace. However, anonymous namespaces can't help out here, because a new anonymous namespace will be created in each translation unit that includes Abc.hpp
. That will lead to issues if your base class has e.g. static members.
我不喜欢的一件事是创建“evil”命名空间。但是,匿名命名空间在这里无济于事,因为将在每个包含Abc.hpp
. 如果您的基类具有例如静态成员,这将导致问题。
Edit:Nevermind, the assignment operator (i.e. Abc bla = evil::Abc(9)
) also works, because evil:Abc
can be implicitly converted to Abc
because that constructor exists.
编辑:没关系,赋值运算符(即Abc bla = evil::Abc(9)
)也有效,因为evil:Abc
可以隐式转换为,Abc
因为该构造函数存在。
Edit 2:You might run into a lot of trouble once there's nested namespaces involved. This happens as soon as there's an #include
in the original Abc.hpp
, because it will now be nested inside the evil
namespace. If you know all of the includes, you could include them before declaring the evil
namespace. Things get real ugly, real quick though.
编辑 2:一旦涉及嵌套命名空间,您可能会遇到很多麻烦。只要#include
原始 中有 an 就会发生这种情况Abc.hpp
,因为它现在将嵌套在evil
命名空间内。如果您知道所有包含,则可以在声明evil
名称空间之前包含它们。事情变得非常丑陋,但很快。
回答by kfsone
There's no specific mechanism for doing this directly in the current C++, but there are several ways you can achieve something like it at the cost of some boiler-plate work:
在当前的 C++ 中没有直接执行此操作的特定机制,但是有几种方法可以以一些样板工作为代价来实现类似的目标:
Method 1:
方法一:
// foo.h
class Foo {
private: // stuff
public: // stuff
private:
// All this crap is private. Pretend like I didn't expose it.
// yeah, I know, you have to compile it, and it probably adds
// dependencies you don't want to #include, like <string>
// or boost, but suck it up, cupcake. Stroustrup hates life.
void internalHelper(std::string&, std::vector&, boost::everything&);
};
Method 2:
方法二:
// foo.h
class Foo {
private: // stuff
public: // stuff
};
// fooimpl.h
// Internal file, do not export with the API.
class FooImpl : public Foo {
private: // stuff
public: // stuff
// So yeah, you have to go thru a cast and an extra include
// if you want to access this. Suck it up, cupcake.
void internalHelper(std::string&, std::vector&, boost::everything&);
};
Method 3:
方法三:
// foo.h
class Foo {
private: // stuff
public: // stuff
// For the private api: this is the worst approach, since it
// exposes stuff and forces include/cruft on consumers.
friend void foo_internalHelper(std::string&, std::vector&, boost::everything&);
};
// foo.cpp
// don't make it static or anyone can make their own as a way to
// back door into our class.
void foo_internalHelper(...);
Method 4:
方法四:
// foo.h
class Foo {
private: // stuff
public: // stuff
// No dependencies, but nothing stops an end-user from creating
// a FooPrivate themselves...
friend class FooPrivate;
};
// foo1.cpp
class FooPrivate {
public:
void fooInternalHelper(Foo* f) {
f->m_privateInternalYouCantSeeMe = "Oh, but I can";
}
};
回答by kfsone
You cannot extend the class Abc
, period!
你不能延长课程Abc
,期间!
The only way out are freestanding functions like
唯一的出路是独立的功能,如
Abc add(const Abc& a, int b);