PIMPL idiom for a pointer to a class in C++
I have a working interface for two programs (ProgramA
and ProgramB
) that I would like to improve decoupling both programs as much as possible. The case that I want to cover is making a call from ProgramA
to a class from ProgramB
(Compute_Prop
) that can only be initialized with some arguments which I do not now in advance. Hence, I use a pointer in the header. Currently, I have something like this:
interface.h
#include "programB.h" // loads Compute_Prop
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
Compute_Prop* compute;
;
interface.cpp
#include "programB.h"
#include "interface.h"
#include "programA.h"
Compute::Compute() = default;
Compute::~Compute()
delete compute;
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new Compute_Prop( &data, arg2 );
Then, I try to imitate the PIMPL idiom with the following
interface.h
#include "programB.h" // loads Compute_Prop
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
class PIMPL;
PIMPL* compute;
;
interface.cpp
#include "programB.h"
#include "interface.h"
#include "programA.h"
Compute::PIMPL = Compute_Prop;
Compute::Compute() = default;
Compute::~Compute()
delete compute;
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new Compute_Prop( &data, arg2 );
but the compiler says:
error: expected unqualified-id
Compute::PIMPL = Compute_Prop;
^
I guess that it has something to do with Compute_Prop not having
an empty constructor. I can't come up with something that works. What should I do? Something like a pointer to a pointer, maybe? As a restriction, I cannot modify programB
.
Note: As it is probably already clear from above, my understanding of low level C++/C is scarce.
EDIT: I introduced the corrections suggested by @n.m. and @Matthieu Brucher
c++ c++11 pointers pimpl-idiom
|
show 1 more comment
I have a working interface for two programs (ProgramA
and ProgramB
) that I would like to improve decoupling both programs as much as possible. The case that I want to cover is making a call from ProgramA
to a class from ProgramB
(Compute_Prop
) that can only be initialized with some arguments which I do not now in advance. Hence, I use a pointer in the header. Currently, I have something like this:
interface.h
#include "programB.h" // loads Compute_Prop
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
Compute_Prop* compute;
;
interface.cpp
#include "programB.h"
#include "interface.h"
#include "programA.h"
Compute::Compute() = default;
Compute::~Compute()
delete compute;
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new Compute_Prop( &data, arg2 );
Then, I try to imitate the PIMPL idiom with the following
interface.h
#include "programB.h" // loads Compute_Prop
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
class PIMPL;
PIMPL* compute;
;
interface.cpp
#include "programB.h"
#include "interface.h"
#include "programA.h"
Compute::PIMPL = Compute_Prop;
Compute::Compute() = default;
Compute::~Compute()
delete compute;
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new Compute_Prop( &data, arg2 );
but the compiler says:
error: expected unqualified-id
Compute::PIMPL = Compute_Prop;
^
I guess that it has something to do with Compute_Prop not having
an empty constructor. I can't come up with something that works. What should I do? Something like a pointer to a pointer, maybe? As a restriction, I cannot modify programB
.
Note: As it is probably already clear from above, my understanding of low level C++/C is scarce.
EDIT: I introduced the corrections suggested by @n.m. and @Matthieu Brucher
c++ c++11 pointers pimpl-idiom
1
Your member declaration syntax is wrong throughout. You are not supposed to repeat the class name inside the class. So noCompute::Compute()
, justCompute()
. I have no idea why some compilers accept the syntax you are using, it's totally illegal.
– n.m.
Nov 13 '18 at 19:37
3
You cannot assign types in C++. Once you declareclass PIMPL;
it expects that there will be a class namedPIMPL
. Pointer declared asPIMPL* ptr;
will always have the typePIMPL
of that promised class.Compute::PIMPL = Compute_Prop;
is not possible, becausePIMPL
andCompute_Prop
are both immutable types. It won't convert allPIMPL
s intoCompute_Prop
s.
– Quimby
Nov 13 '18 at 19:57
1
if ( compute != nullptr ) delete compute; compute = nullptr; No!! just delete it, or even better, use std::unique_ptr!!
– Matthieu Brucher
Nov 13 '18 at 20:09
1
Compute::PIMPL
is a type, you cannot have thistype = value
syntax. You need a name. Something likeCompute::compute
perhaps.Compute::PIMPL Compute::compute = ...
.
– n.m.
Nov 13 '18 at 20:28
1
yes, delete already does the check, it's a useless redundancy. And if you have problems with using unique_ptr, then it means that you have other things to fix as well, ceuase that's how the pimlp should be handled.
– Matthieu Brucher
Nov 14 '18 at 14:00
|
show 1 more comment
I have a working interface for two programs (ProgramA
and ProgramB
) that I would like to improve decoupling both programs as much as possible. The case that I want to cover is making a call from ProgramA
to a class from ProgramB
(Compute_Prop
) that can only be initialized with some arguments which I do not now in advance. Hence, I use a pointer in the header. Currently, I have something like this:
interface.h
#include "programB.h" // loads Compute_Prop
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
Compute_Prop* compute;
;
interface.cpp
#include "programB.h"
#include "interface.h"
#include "programA.h"
Compute::Compute() = default;
Compute::~Compute()
delete compute;
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new Compute_Prop( &data, arg2 );
Then, I try to imitate the PIMPL idiom with the following
interface.h
#include "programB.h" // loads Compute_Prop
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
class PIMPL;
PIMPL* compute;
;
interface.cpp
#include "programB.h"
#include "interface.h"
#include "programA.h"
Compute::PIMPL = Compute_Prop;
Compute::Compute() = default;
Compute::~Compute()
delete compute;
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new Compute_Prop( &data, arg2 );
but the compiler says:
error: expected unqualified-id
Compute::PIMPL = Compute_Prop;
^
I guess that it has something to do with Compute_Prop not having
an empty constructor. I can't come up with something that works. What should I do? Something like a pointer to a pointer, maybe? As a restriction, I cannot modify programB
.
Note: As it is probably already clear from above, my understanding of low level C++/C is scarce.
EDIT: I introduced the corrections suggested by @n.m. and @Matthieu Brucher
c++ c++11 pointers pimpl-idiom
I have a working interface for two programs (ProgramA
and ProgramB
) that I would like to improve decoupling both programs as much as possible. The case that I want to cover is making a call from ProgramA
to a class from ProgramB
(Compute_Prop
) that can only be initialized with some arguments which I do not now in advance. Hence, I use a pointer in the header. Currently, I have something like this:
interface.h
#include "programB.h" // loads Compute_Prop
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
Compute_Prop* compute;
;
interface.cpp
#include "programB.h"
#include "interface.h"
#include "programA.h"
Compute::Compute() = default;
Compute::~Compute()
delete compute;
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new Compute_Prop( &data, arg2 );
Then, I try to imitate the PIMPL idiom with the following
interface.h
#include "programB.h" // loads Compute_Prop
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
class PIMPL;
PIMPL* compute;
;
interface.cpp
#include "programB.h"
#include "interface.h"
#include "programA.h"
Compute::PIMPL = Compute_Prop;
Compute::Compute() = default;
Compute::~Compute()
delete compute;
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new Compute_Prop( &data, arg2 );
but the compiler says:
error: expected unqualified-id
Compute::PIMPL = Compute_Prop;
^
I guess that it has something to do with Compute_Prop not having
an empty constructor. I can't come up with something that works. What should I do? Something like a pointer to a pointer, maybe? As a restriction, I cannot modify programB
.
Note: As it is probably already clear from above, my understanding of low level C++/C is scarce.
EDIT: I introduced the corrections suggested by @n.m. and @Matthieu Brucher
c++ c++11 pointers pimpl-idiom
c++ c++11 pointers pimpl-idiom
edited Nov 18 '18 at 21:46
Zythos
asked Nov 13 '18 at 19:26
ZythosZythos
16118
16118
1
Your member declaration syntax is wrong throughout. You are not supposed to repeat the class name inside the class. So noCompute::Compute()
, justCompute()
. I have no idea why some compilers accept the syntax you are using, it's totally illegal.
– n.m.
Nov 13 '18 at 19:37
3
You cannot assign types in C++. Once you declareclass PIMPL;
it expects that there will be a class namedPIMPL
. Pointer declared asPIMPL* ptr;
will always have the typePIMPL
of that promised class.Compute::PIMPL = Compute_Prop;
is not possible, becausePIMPL
andCompute_Prop
are both immutable types. It won't convert allPIMPL
s intoCompute_Prop
s.
– Quimby
Nov 13 '18 at 19:57
1
if ( compute != nullptr ) delete compute; compute = nullptr; No!! just delete it, or even better, use std::unique_ptr!!
– Matthieu Brucher
Nov 13 '18 at 20:09
1
Compute::PIMPL
is a type, you cannot have thistype = value
syntax. You need a name. Something likeCompute::compute
perhaps.Compute::PIMPL Compute::compute = ...
.
– n.m.
Nov 13 '18 at 20:28
1
yes, delete already does the check, it's a useless redundancy. And if you have problems with using unique_ptr, then it means that you have other things to fix as well, ceuase that's how the pimlp should be handled.
– Matthieu Brucher
Nov 14 '18 at 14:00
|
show 1 more comment
1
Your member declaration syntax is wrong throughout. You are not supposed to repeat the class name inside the class. So noCompute::Compute()
, justCompute()
. I have no idea why some compilers accept the syntax you are using, it's totally illegal.
– n.m.
Nov 13 '18 at 19:37
3
You cannot assign types in C++. Once you declareclass PIMPL;
it expects that there will be a class namedPIMPL
. Pointer declared asPIMPL* ptr;
will always have the typePIMPL
of that promised class.Compute::PIMPL = Compute_Prop;
is not possible, becausePIMPL
andCompute_Prop
are both immutable types. It won't convert allPIMPL
s intoCompute_Prop
s.
– Quimby
Nov 13 '18 at 19:57
1
if ( compute != nullptr ) delete compute; compute = nullptr; No!! just delete it, or even better, use std::unique_ptr!!
– Matthieu Brucher
Nov 13 '18 at 20:09
1
Compute::PIMPL
is a type, you cannot have thistype = value
syntax. You need a name. Something likeCompute::compute
perhaps.Compute::PIMPL Compute::compute = ...
.
– n.m.
Nov 13 '18 at 20:28
1
yes, delete already does the check, it's a useless redundancy. And if you have problems with using unique_ptr, then it means that you have other things to fix as well, ceuase that's how the pimlp should be handled.
– Matthieu Brucher
Nov 14 '18 at 14:00
1
1
Your member declaration syntax is wrong throughout. You are not supposed to repeat the class name inside the class. So no
Compute::Compute()
, just Compute()
. I have no idea why some compilers accept the syntax you are using, it's totally illegal.– n.m.
Nov 13 '18 at 19:37
Your member declaration syntax is wrong throughout. You are not supposed to repeat the class name inside the class. So no
Compute::Compute()
, just Compute()
. I have no idea why some compilers accept the syntax you are using, it's totally illegal.– n.m.
Nov 13 '18 at 19:37
3
3
You cannot assign types in C++. Once you declare
class PIMPL;
it expects that there will be a class named PIMPL
. Pointer declared as PIMPL* ptr;
will always have the type PIMPL
of that promised class. Compute::PIMPL = Compute_Prop;
is not possible, because PIMPL
and Compute_Prop
are both immutable types. It won't convert all PIMPL
s into Compute_Prop
s.– Quimby
Nov 13 '18 at 19:57
You cannot assign types in C++. Once you declare
class PIMPL;
it expects that there will be a class named PIMPL
. Pointer declared as PIMPL* ptr;
will always have the type PIMPL
of that promised class. Compute::PIMPL = Compute_Prop;
is not possible, because PIMPL
and Compute_Prop
are both immutable types. It won't convert all PIMPL
s into Compute_Prop
s.– Quimby
Nov 13 '18 at 19:57
1
1
if ( compute != nullptr ) delete compute; compute = nullptr; No!! just delete it, or even better, use std::unique_ptr!!
– Matthieu Brucher
Nov 13 '18 at 20:09
if ( compute != nullptr ) delete compute; compute = nullptr; No!! just delete it, or even better, use std::unique_ptr!!
– Matthieu Brucher
Nov 13 '18 at 20:09
1
1
Compute::PIMPL
is a type, you cannot have this type = value
syntax. You need a name. Something like Compute::compute
perhaps. Compute::PIMPL Compute::compute = ...
.– n.m.
Nov 13 '18 at 20:28
Compute::PIMPL
is a type, you cannot have this type = value
syntax. You need a name. Something like Compute::compute
perhaps. Compute::PIMPL Compute::compute = ...
.– n.m.
Nov 13 '18 at 20:28
1
1
yes, delete already does the check, it's a useless redundancy. And if you have problems with using unique_ptr, then it means that you have other things to fix as well, ceuase that's how the pimlp should be handled.
– Matthieu Brucher
Nov 14 '18 at 14:00
yes, delete already does the check, it's a useless redundancy. And if you have problems with using unique_ptr, then it means that you have other things to fix as well, ceuase that's how the pimlp should be handled.
– Matthieu Brucher
Nov 14 '18 at 14:00
|
show 1 more comment
2 Answers
2
active
oldest
votes
Your implementation should use an interface (or in fact a class with only abstract methods) as a base class.
You cannot assign types in C++. You can only create typedefs and aliases, like that:
using PIMPLType = Compute_Prop;
However this won't work in your case.
This is how it should be implemented (also with possibility of multiple implementations):
class IImplementation
public:
virtual void saySomething() = 0;
;
class ImplementationA : public IImplementation
public:
virtual void saySomething() override
std::cout << "A";
;
class ImplementationB : public IImplementation
public:
virtual void saySomething() override
std::cout << "B";
;
class Foo
IImplementation *pimpl;
public:
Foo()
: pimpl(new ImplementationA)
~Foo() delete pimpl;
void saySomething()
pimpl->saySomething();
;
I will investigate how to materialize it. Also, a point of concern is speed, methods ofCompute
are called millions of times and can take either milliseconds or minutes, hours.
– Zythos
Nov 14 '18 at 14:02
add a comment |
I may have come across a simple solution. I post it here so you can judge if it is adequate, or even if it can be improved --- sure. I am convinced that runtime polymorphism is not needed, not even polymorphism. The member variable compute
is going to be a pointer to a Compute_Prop
type anyway. Then, given that performance is critical here: why running the extra overhead of virtual member functions?
The point here is to reach an implementation that hides the inclusion of Compute_Prop
without loosing performance. How? This particular solution uses a templated class and then explicit instantiation. The point is that instantiation can be done in the implementation. Got it from a Fluent C++ blog post. Also, this post has hints for how the implementation should be done. A prototype would be:
interface.h
template <typename T>
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
T* compute; // No need to state that is going to be T:=Compute_Prop
;
interface_impl.h
#include "interface.h"
#include "programA.h"
template <typename T>
Compute::Compute() = default;
template <typename T>
Compute::~Compute()
delete compute;
template <typename T>
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new T( &data, arg2 );
interface.cpp
#include "interface.h"
#include "interface_impl.h"
#include "programA.h"
#include "programB.h" // loads Compute_Prop
int main(int argc, char** argv)
template class Compute<Compute_Prop>;
Another related question that might be useful for those with the same dilemma.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53288192%2fpimpl-idiom-for-a-pointer-to-a-class-in-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Your implementation should use an interface (or in fact a class with only abstract methods) as a base class.
You cannot assign types in C++. You can only create typedefs and aliases, like that:
using PIMPLType = Compute_Prop;
However this won't work in your case.
This is how it should be implemented (also with possibility of multiple implementations):
class IImplementation
public:
virtual void saySomething() = 0;
;
class ImplementationA : public IImplementation
public:
virtual void saySomething() override
std::cout << "A";
;
class ImplementationB : public IImplementation
public:
virtual void saySomething() override
std::cout << "B";
;
class Foo
IImplementation *pimpl;
public:
Foo()
: pimpl(new ImplementationA)
~Foo() delete pimpl;
void saySomething()
pimpl->saySomething();
;
I will investigate how to materialize it. Also, a point of concern is speed, methods ofCompute
are called millions of times and can take either milliseconds or minutes, hours.
– Zythos
Nov 14 '18 at 14:02
add a comment |
Your implementation should use an interface (or in fact a class with only abstract methods) as a base class.
You cannot assign types in C++. You can only create typedefs and aliases, like that:
using PIMPLType = Compute_Prop;
However this won't work in your case.
This is how it should be implemented (also with possibility of multiple implementations):
class IImplementation
public:
virtual void saySomething() = 0;
;
class ImplementationA : public IImplementation
public:
virtual void saySomething() override
std::cout << "A";
;
class ImplementationB : public IImplementation
public:
virtual void saySomething() override
std::cout << "B";
;
class Foo
IImplementation *pimpl;
public:
Foo()
: pimpl(new ImplementationA)
~Foo() delete pimpl;
void saySomething()
pimpl->saySomething();
;
I will investigate how to materialize it. Also, a point of concern is speed, methods ofCompute
are called millions of times and can take either milliseconds or minutes, hours.
– Zythos
Nov 14 '18 at 14:02
add a comment |
Your implementation should use an interface (or in fact a class with only abstract methods) as a base class.
You cannot assign types in C++. You can only create typedefs and aliases, like that:
using PIMPLType = Compute_Prop;
However this won't work in your case.
This is how it should be implemented (also with possibility of multiple implementations):
class IImplementation
public:
virtual void saySomething() = 0;
;
class ImplementationA : public IImplementation
public:
virtual void saySomething() override
std::cout << "A";
;
class ImplementationB : public IImplementation
public:
virtual void saySomething() override
std::cout << "B";
;
class Foo
IImplementation *pimpl;
public:
Foo()
: pimpl(new ImplementationA)
~Foo() delete pimpl;
void saySomething()
pimpl->saySomething();
;
Your implementation should use an interface (or in fact a class with only abstract methods) as a base class.
You cannot assign types in C++. You can only create typedefs and aliases, like that:
using PIMPLType = Compute_Prop;
However this won't work in your case.
This is how it should be implemented (also with possibility of multiple implementations):
class IImplementation
public:
virtual void saySomething() = 0;
;
class ImplementationA : public IImplementation
public:
virtual void saySomething() override
std::cout << "A";
;
class ImplementationB : public IImplementation
public:
virtual void saySomething() override
std::cout << "B";
;
class Foo
IImplementation *pimpl;
public:
Foo()
: pimpl(new ImplementationA)
~Foo() delete pimpl;
void saySomething()
pimpl->saySomething();
;
answered Nov 13 '18 at 20:06
Poeta KoduPoeta Kodu
648312
648312
I will investigate how to materialize it. Also, a point of concern is speed, methods ofCompute
are called millions of times and can take either milliseconds or minutes, hours.
– Zythos
Nov 14 '18 at 14:02
add a comment |
I will investigate how to materialize it. Also, a point of concern is speed, methods ofCompute
are called millions of times and can take either milliseconds or minutes, hours.
– Zythos
Nov 14 '18 at 14:02
I will investigate how to materialize it. Also, a point of concern is speed, methods of
Compute
are called millions of times and can take either milliseconds or minutes, hours.– Zythos
Nov 14 '18 at 14:02
I will investigate how to materialize it. Also, a point of concern is speed, methods of
Compute
are called millions of times and can take either milliseconds or minutes, hours.– Zythos
Nov 14 '18 at 14:02
add a comment |
I may have come across a simple solution. I post it here so you can judge if it is adequate, or even if it can be improved --- sure. I am convinced that runtime polymorphism is not needed, not even polymorphism. The member variable compute
is going to be a pointer to a Compute_Prop
type anyway. Then, given that performance is critical here: why running the extra overhead of virtual member functions?
The point here is to reach an implementation that hides the inclusion of Compute_Prop
without loosing performance. How? This particular solution uses a templated class and then explicit instantiation. The point is that instantiation can be done in the implementation. Got it from a Fluent C++ blog post. Also, this post has hints for how the implementation should be done. A prototype would be:
interface.h
template <typename T>
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
T* compute; // No need to state that is going to be T:=Compute_Prop
;
interface_impl.h
#include "interface.h"
#include "programA.h"
template <typename T>
Compute::Compute() = default;
template <typename T>
Compute::~Compute()
delete compute;
template <typename T>
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new T( &data, arg2 );
interface.cpp
#include "interface.h"
#include "interface_impl.h"
#include "programA.h"
#include "programB.h" // loads Compute_Prop
int main(int argc, char** argv)
template class Compute<Compute_Prop>;
Another related question that might be useful for those with the same dilemma.
add a comment |
I may have come across a simple solution. I post it here so you can judge if it is adequate, or even if it can be improved --- sure. I am convinced that runtime polymorphism is not needed, not even polymorphism. The member variable compute
is going to be a pointer to a Compute_Prop
type anyway. Then, given that performance is critical here: why running the extra overhead of virtual member functions?
The point here is to reach an implementation that hides the inclusion of Compute_Prop
without loosing performance. How? This particular solution uses a templated class and then explicit instantiation. The point is that instantiation can be done in the implementation. Got it from a Fluent C++ blog post. Also, this post has hints for how the implementation should be done. A prototype would be:
interface.h
template <typename T>
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
T* compute; // No need to state that is going to be T:=Compute_Prop
;
interface_impl.h
#include "interface.h"
#include "programA.h"
template <typename T>
Compute::Compute() = default;
template <typename T>
Compute::~Compute()
delete compute;
template <typename T>
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new T( &data, arg2 );
interface.cpp
#include "interface.h"
#include "interface_impl.h"
#include "programA.h"
#include "programB.h" // loads Compute_Prop
int main(int argc, char** argv)
template class Compute<Compute_Prop>;
Another related question that might be useful for those with the same dilemma.
add a comment |
I may have come across a simple solution. I post it here so you can judge if it is adequate, or even if it can be improved --- sure. I am convinced that runtime polymorphism is not needed, not even polymorphism. The member variable compute
is going to be a pointer to a Compute_Prop
type anyway. Then, given that performance is critical here: why running the extra overhead of virtual member functions?
The point here is to reach an implementation that hides the inclusion of Compute_Prop
without loosing performance. How? This particular solution uses a templated class and then explicit instantiation. The point is that instantiation can be done in the implementation. Got it from a Fluent C++ blog post. Also, this post has hints for how the implementation should be done. A prototype would be:
interface.h
template <typename T>
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
T* compute; // No need to state that is going to be T:=Compute_Prop
;
interface_impl.h
#include "interface.h"
#include "programA.h"
template <typename T>
Compute::Compute() = default;
template <typename T>
Compute::~Compute()
delete compute;
template <typename T>
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new T( &data, arg2 );
interface.cpp
#include "interface.h"
#include "interface_impl.h"
#include "programA.h"
#include "programB.h" // loads Compute_Prop
int main(int argc, char** argv)
template class Compute<Compute_Prop>;
Another related question that might be useful for those with the same dilemma.
I may have come across a simple solution. I post it here so you can judge if it is adequate, or even if it can be improved --- sure. I am convinced that runtime polymorphism is not needed, not even polymorphism. The member variable compute
is going to be a pointer to a Compute_Prop
type anyway. Then, given that performance is critical here: why running the extra overhead of virtual member functions?
The point here is to reach an implementation that hides the inclusion of Compute_Prop
without loosing performance. How? This particular solution uses a templated class and then explicit instantiation. The point is that instantiation can be done in the implementation. Got it from a Fluent C++ blog post. Also, this post has hints for how the implementation should be done. A prototype would be:
interface.h
template <typename T>
class Compute
public:
Compute();
Compute(targ1 arg1, targ2 arg2);
~Compute();
// some methods ...
private:
T* compute; // No need to state that is going to be T:=Compute_Prop
;
interface_impl.h
#include "interface.h"
#include "programA.h"
template <typename T>
Compute::Compute() = default;
template <typename T>
Compute::~Compute()
delete compute;
template <typename T>
Compute::Compute(arg1, arg2)
// do something ... to get data
compute = new T( &data, arg2 );
interface.cpp
#include "interface.h"
#include "interface_impl.h"
#include "programA.h"
#include "programB.h" // loads Compute_Prop
int main(int argc, char** argv)
template class Compute<Compute_Prop>;
Another related question that might be useful for those with the same dilemma.
edited Nov 18 '18 at 11:06
answered Nov 18 '18 at 1:07
ZythosZythos
16118
16118
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53288192%2fpimpl-idiom-for-a-pointer-to-a-class-in-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Your member declaration syntax is wrong throughout. You are not supposed to repeat the class name inside the class. So no
Compute::Compute()
, justCompute()
. I have no idea why some compilers accept the syntax you are using, it's totally illegal.– n.m.
Nov 13 '18 at 19:37
3
You cannot assign types in C++. Once you declare
class PIMPL;
it expects that there will be a class namedPIMPL
. Pointer declared asPIMPL* ptr;
will always have the typePIMPL
of that promised class.Compute::PIMPL = Compute_Prop;
is not possible, becausePIMPL
andCompute_Prop
are both immutable types. It won't convert allPIMPL
s intoCompute_Prop
s.– Quimby
Nov 13 '18 at 19:57
1
if ( compute != nullptr ) delete compute; compute = nullptr; No!! just delete it, or even better, use std::unique_ptr!!
– Matthieu Brucher
Nov 13 '18 at 20:09
1
Compute::PIMPL
is a type, you cannot have thistype = value
syntax. You need a name. Something likeCompute::compute
perhaps.Compute::PIMPL Compute::compute = ...
.– n.m.
Nov 13 '18 at 20:28
1
yes, delete already does the check, it's a useless redundancy. And if you have problems with using unique_ptr, then it means that you have other things to fix as well, ceuase that's how the pimlp should be handled.
– Matthieu Brucher
Nov 14 '18 at 14:00