C++ 上的部分类定义?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/140935/
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
Partial class definition on C++?
提问by Edwin Jarvis
Anyone knows if is possible to have partial class definition on C++ ?
任何人都知道是否可以在 C++ 上定义部分类?
Something like:
就像是:
file1.h:
文件1.h:
class Test { public: int test1(); };
file2.h:
文件2.h:
class Test { public: int test2(); };
For me it seems quite useful for definining multi-platform classes that have common functions between them that are platform-independent because inheritance is a cost to pay that is non-useful for multi-platform classes.
对我来说,定义多平台类似乎非常有用,这些类在它们之间具有平台无关的公共功能,因为继承是一种支付成本,对多平台类没有用。
I mean you will never have two multi-platform specialization instances at runtime, only at compile time. Inheritance could be useful to fulfill your public interface needs but after that it won't add anything useful at runtime, just costs.
我的意思是你永远不会在运行时有两个多平台专业化实例,只有在编译时。继承可能有助于满足您的公共接口需求,但之后它不会在运行时添加任何有用的东西,只会增加成本。
Also you will have to use an ugly #ifdef to use the class because you can't make an instance from an abstract class:
此外,您将不得不使用丑陋的 #ifdef 来使用该类,因为您无法从抽象类创建实例:
class genericTest { public: int genericMethod(); };
Then let's say for win32:
然后让我们说win32:
class win32Test: public genericTest { public: int win32Method(); };
And maybe:
有可能:
class macTest: public genericTest { public: int macMethod(); };
Let's think that both win32Method() and macMethod() calls genericMethod(), and you will have to use the class like this:
让我们认为 win32Method() 和 macMethod() 都调用了 genericMethod(),你将不得不像这样使用这个类:
#ifdef _WIN32 genericTest *test = new win32Test(); #elif MAC genericTest *test = new macTest(); #endif test->genericMethod();
Now thinking a while the inheritance was only useful for giving them both a genericMethod() that is dependent on the platform-specific one, but you have the cost of calling two constructors because of that. Also you have ugly #ifdef scattered around the code.
现在考虑一下,继承仅用于为它们提供一个依赖于特定平台的 genericMethod() ,但是因此您需要调用两个构造函数。你也有丑陋的#ifdef 散布在代码周围。
That's why I was looking for partial classes. I could at compile-time define the specific platform dependent partial end, of course that on this silly example I still need an ugly #ifdef inside genericMethod() but there is another ways to avoid that.
这就是我寻找部分课程的原因。我可以在编译时定义特定平台相关的部分结束,当然,在这个愚蠢的例子中,我仍然需要在 genericMethod() 中使用丑陋的 #ifdef,但还有另一种方法可以避免这种情况。
采纳答案by John Millikin
This is not possible in C++, it will give you an error about redefining already-defined classes. If you'd like to share behavior, consider inheritance.
这在 C++ 中是不可能的,它会给你一个关于重新定义已经定义的类的错误。如果您想共享行为,请考虑继承。
回答by Jamie
Try inheritance
尝试继承
Specifically
具体来说
class AllPlatforms {
public:
int common();
};
and then
进而
class PlatformA : public AllPlatforms {
public:
int specific();
};
回答by Steve Jessop
You can't partially define classes in C++.
您不能在 C++ 中部分定义类。
Here's a way to get the "polymorphism, where there's only one subclass" effect you're after without overhead and with a bare minimum of #define or code duplication. It's called simulated dynamic binding:
这是一种获得“多态性,其中只有一个子类”效果的方法,无需开销,只需最少的 #define 或代码重复。它被称为模拟动态绑定:
template <typename T>
class genericTest {
public:
void genericMethod() {
// do some generic things
std::cout << "Could be any platform, I dunno" << std::endl;
// base class can call a method in the child with static_cast
(static_cast<T*>(this))->doClassDependentThing();
}
};
#ifdef _WIN32
typedef Win32Test Test;
#elif MAC
typedef MacTest Test;
#endif
Then off in some other headers you'll have:
然后在其他一些标题中关闭,您将拥有:
class Win32Test : public genericTest<Win32Test> {
public:
void win32Method() {
// windows-specific stuff:
std::cout << "I'm in windows" << std::endl;
// we can call a method in the base class
genericMethod();
// more windows-specific stuff...
}
void doClassDependentThing() {
std::cout << "Yep, definitely in windows" << std::endl;
}
};
and
和
class MacTest : public genericTest<MacTest> {
public:
void macMethod() {
// mac-specific stuff:
std::cout << "I'm in MacOS" << std::endl;
// we can call a method in the base class
genericMethod();
// more mac-specific stuff...
}
void doClassDependentThing() {
std::cout << "Yep, definitely in MacOS" << std::endl;
}
};
This gives you proper polymorphism at compile time. genericTest can non-virtually call doClassDependentThing in a way that gives it the platform version, (almost like a virtual method), and when win32Method calls genericMethod it of course gets the base class version.
这在编译时为您提供了适当的多态性。genericTest 可以以提供平台版本的方式非虚拟地调用 doClassDependentThing(几乎类似于虚拟方法),并且当 win32Method 调用 genericMethod 时,它当然会获取基类版本。
This creates no overhead associated with virtual calls - you get the same performance as if you'd typed out two big classes with no shared code. It may create a non-virtual call overhead at con(de)struction, but if the con(de)structor for genericTest is inlined you should be fine, and that overhead is in any case no worse than having a genericInit method that's called by both platforms.
这不会产生与虚拟调用相关的开销 - 您获得的性能与在没有共享代码的情况下键入两个大类一样。它可能会在 con(de)struction 中创建非虚拟调用开销,但是如果内联了 genericTest 的 con(de)structor,则应该没问题,并且该开销在任何情况下都不会比调用 genericInit 方法更糟两个平台。
Client code just creates instances of Test, and can call methods on them which are either in genericTest or in the correct version for the platform. To help with type safety in code which doesn't care about the platform and doesn't want to accidentally make use of platform-specific calls, you could additionally do:
客户端代码只是创建 Test 的实例,并且可以调用它们的方法,这些方法要么是 genericTest 要么是平台的正确版本。为了帮助不关心平台并且不想意外使用特定于平台的调用的代码中的类型安全,您还可以执行以下操作:
#ifdef _WIN32
typedef genericTest<Win32Test> BaseTest;
#elif MAC
typedef genericTest<MacTest> BaseTest;
#endif
You have to be a bit careful using BaseTest, but not much more so than is always the case with base classes in C++. For instance, don't slice it with an ill-judged pass-by-value. And don't instantiate it directly, because if you do and call a method that ends up attempting a "fake virtual" call, you're in trouble. The latter can be enforced by ensuring that all of genericTest's constructors are protected.
使用 BaseTest 时必须小心一点,但不会比使用 C++ 中的基类时更小心。例如,不要使用错误判断的传递值对其进行切片。并且不要直接实例化它,因为如果你这样做并调用一个最终尝试“假虚拟”调用的方法,你就有麻烦了。后者可以通过确保所有 genericTest 的构造函数都受到保护来强制执行。
回答by PiNoYBoY82
or you could try PIMPL
或者你可以试试 PIMPL
common header file:
通用头文件:
class Test
{
public:
...
void common();
...
private:
class TestImpl;
TestImpl* m_customImpl;
};
Then create the cpp files doing the custom implementations that are platform specific.
然后创建执行特定于平台的自定义实现的 cpp 文件。
回答by PiNoYBoY82
#include will work as that is preprocessor stuff.
class Foo
{
#include "FooFile_Private.h"
}
////////
FooFile_Private.h:
private:
void DoSg();
回答by pdc
How about this:
这个怎么样:
class WindowsFuncs { public: int f(); int winf(); };
class MacFuncs { public: int f(); int macf(); }
class Funcs
#ifdef Windows
: public WindowsFuncs
#else
: public MacFuncs
#endif
{
public:
Funcs();
int g();
};
Now Funcs
is a class known at compile-time, so no overheads are caused by abstract base classes or whatever.
NowFuncs
是一个在编译时已知的类,因此抽象基类或其他任何东西都不会引起开销。
回答by eduffy
Nope.
不。
But, you may want to look up a technique called "Policy Classes". Basically, you make micro-classes (that aren't useful on their own) then glue them together at some later point.
但是,您可能想要查找一种称为“策略类”的技术。基本上,您制作微课程(它们本身没有用),然后在稍后的某个时间将它们粘合在一起。
回答by SONIC3D
Dirty but practical way is using #include preprocessor:
肮脏但实用的方法是使用 #include 预处理器:
Test.h:
测试.h:
#ifndef TEST_H
#define TEST_H
class Test
{
public:
Test(void);
virtual ~Test(void);
#include "Test_Partial_Win32.h"
#include "Test_Partial_OSX.h"
};
#endif // !TEST_H
Test_Partial_OSX.h:
Test_Partial_OSX.h:
// This file should be included in Test.h only.
#ifdef MAC
public:
int macMethod();
#endif // MAC
Test_Partial_WIN32.h:
Test_Partial_WIN32.h:
// This file should be included in Test.h only.
#ifdef _WIN32
public:
int win32Method();
#endif // _WIN32
Test.cpp:
测试.cpp:
// Implement common member function of class Test in this file.
#include "stdafx.h"
#include "Test.h"
Test::Test(void)
{
}
Test::~Test(void)
{
}
Test_Partial_OSX.cpp:
Test_Partial_OSX.cpp:
// Implement OSX platform specific function of class Test in this file.
#include "stdafx.h"
#include "Test.h"
#ifdef MAC
int Test::macMethod()
{
return 0;
}
#endif // MAC
Test_Partial_WIN32.cpp:
Test_Partial_WIN32.cpp:
// Implement WIN32 platform specific function of class Test in this file.
#include "stdafx.h"
#include "Test.h"
#ifdef _WIN32
int Test::win32Method()
{
return 0;
}
#endif // _WIN32
回答by Lev
Either use inheritance, as Jamie said, or #ifdef to make different parts compile on different platforms.
正如杰米所说,要么使用继承,要么使用 #ifdef 使不同的部分在不同的平台上编译。
回答by Hugh Allen
Since headers are just textually inserted, one of them could omit the "class Test {" and "}" and be #included in the middle of the other.
由于标题只是文本插入,其中一个可以省略“class Test {”和“}”,并在另一个中间#included。
I've actually seen this in production code, albeit Delphi not C++. It particularly annoyed me because it broke the IDE's code navigation features.
我实际上已经在生产代码中看到了这一点,尽管 Delphi 不是 C++。它让我特别恼火,因为它破坏了 IDE 的代码导航功能。