|
Hi All
When I draw button with style :
ModifyStyle(0, BS_OWNERDRAW);
but function DrawItem : no message ODS_DEFAULT.
I can't draw state default of button .
Example : Dialog have edit control and button.
With button no custom : Windows draw focus default button and focus edit control.
With button custom : I can't draw state focus of button when focus edit control .Need press TAB draw state focus of button.
Can you help me ?
Thank.
|
|
|
|
|
Some code segment in chapter 10 of "Windows via C/C++"(5th Edition) is
CEnsureCloseFile hFileSrc = CreateFile(pszFileSrc,
GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_NO_BUFFERING |
FILE_FLAG_OVERLAPPED, NULL);
Here "CEnsureCloseFile" is a class. The Author define Template class "CEnsureCleanup" which was used to clean some objects, then use a this Template define class CEnsureCloseFile
My question is why the HANDLE created by "CreateFile" can be assigned to object hFileSrc . It seems rare. Do you offen do sth like this?
|
|
|
|
|
Since it's just a pointer, it can be set to anything that can handle that appropriately (the constructor for this object likely takes in that type of HANDLE). His class probably just makes sure a file is properly closed without requiring you to explicitly close the file (open file handles can be an issue).
http://en.wikipedia.org/wiki/Assignment_operator_(C%2B%2B)[^]
|
|
|
|
|
|
digitalspace.xjtu wrote: why the HANDLE created by "CreateFile" can be assigned to object hFileSrc .
because the class has an overloaded '=' operator.
i don't have the source, but i imagine it looks like this:
TYPE operator=(TYPE t) {
Cleanup();
m_t = (UINT_PTR) t;
return(*this);
}
i do stuff like this all the time. i have dozen of little classes designed to take a handle of some kind in the constructor and then call the appropriate release/delete in the destructor.
|
|
|
|
|
Oh, it is operator overload , thank you very much
|
|
|
|
|
Hi to all,
I am able to generate DSA 512 bit KeyPair using crypto++ using the following code
<br />
<br />
bool CreateDSAKeys()<br />
{<br />
<br />
CryptoPP::AutoSeededX917RNG<CryptoPP::AES> prng;<br />
<br />
try<br />
{<br />
<br />
CryptoPP::GDSA<CryptoPP::SHA1>::GroupParameters pqg;<br />
pqg.GenerateRandom (prng, CryptoPP::MakeParameters(CryptoPP::Name::ModulusSize (), 512)(CryptoPP::Name::SubgroupOrderSize (), 160));<br />
<br />
OutputData(output, "P ", pqg.GetModulus (), pqg.GetModulus ().ByteCount ());<br />
OutputData(output, "Q ", pqg.GetSubgroupOrder(), pqg.GetSubgroupOrder ().ByteCount ());<br />
OutputData(output, "G ", pqg.GetSubgroupGenerator(), pqg.GetSubgroupGenerator ().ByteCount ());<br />
<br />
CryptoPP::GDSA<CryptoPP::SHA1>::Signer priv;<br />
priv.AccessKey().GenerateRandom(prng, pqg);
DSA::Verifier pub(priv);<br />
<br />
OutputData(output, "X ", priv.GetKey().GetPrivateExponent(), priv.GetKey().GetPrivateExponent().ByteCount ());<br />
OutputData(output, "Y ", pub.GetKey().GetPublicElement(), pub.GetKey().GetPublicElement().ByteCount ());<br />
}<br />
}<br />
But, The length of the PrivateKey x Parameter and the length of the Q parameter are not equal and the values of group parameters are also not constant.
can any one suggest me a way to solve this problem.
Thanks in advance.
|
|
|
|
|
Hi All,
when I build visual studio to create exe file .Then I run exe file ,It will have a process . and I continue to run exe file again . Therefore i will have two process for exe file .
How to Create Single Process in C++ ?
I think we can check process currently if process exist we exit new process.
I try to use singleton but i can not create single process.
Do you have any way ?
Thanks
Thong LT
|
|
|
|
|
|
|
Could someone tell me what is going on here? Please.
I am trying to output audio frequency using waveOutWrite. I am using callback function.
Works as expected.
Now I would like to output the audio using the “loop” parameter in the header.
The header sets WHDR_DONE flag when the loop is done.
Now I needed to “translate “ WHDR_DONE flag to the callabck WOM_DONE message for further processing .
I couldn't make the callback work on event so I used this.( I'll try it again).
<b>I have used this „event“ , it partially works but I have no idea why.</b>
HANDLE event;
event = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD dwWaitResult;
Callback function:
void CALLBACK C_AssynchPlay2::CallbackWaveOutProc(HWAVEOUT hwo,
UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
TRACE("\nvoid CALLBACK C_AssynchPlay2::CallbackWaveOutProc...");
if (uMsg == WOM_DONE)
{
AfxMessageBox("finished "); // gets here
return;
}
Output audio function:
bRC = TRUE;
TRACE("\nInitialize pcm %i ",i );
pcm[i].lFreq = Freq;
pcm[i].dDelay = 1; // Delay; must be < 1
pcm[i].whdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
pcm[i].whdr.dwLoops = 5; // works
if(!pcm[i].C_CreateSinus())
TRACE("\nFailed pcm[i].C_CreateSinus() %i ", i );
HANDLE event;
event = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD dwWaitResult;
mmres = waveOutPrepareHeader(hwout, & pcm[i].whdr, sizeof(WAVEHDR));
if (mmres != MMSYSERR_NOERROR) {ASSERT(0); bOK = FALSE;}
mmres = waveOutWrite(hwout, & pcm[i].whdr, sizeof(WAVEHDR));
TRACE("\nWait event ");
dwWaitResult = WaitForSingleObject(event,INFINITE); //sets WOM_DONE in callback
From here this code never gets processed
TRACE("\nWait event OK ");
AfxMessageBox("Wait event.... ");
return bRC;
Many thanks for your help.
Cheers
Vaclav
|
|
|
|
|
Vaclav_Sal wrote: dwWaitResult = WaitForSingleObject(event,INFINITE); //sets WOM_DONE in callback
You're waiting for an event to be set for an infinite amount of time. I think that it's not returning because the event is never set, and as such the code doesn't progress further to execute your AfxMessageBox.
Have you verified that the WaitForSingleObject call actually returns?
"Real men drive manual transmission" - Rajesh.
|
|
|
|
|
That is my main question. When I comment the WaitForSingleObject out the WOM_DONE get set immediatelly after the waveOutWrite. Not waiting for the header loop flag to indicate completion of the loop. There is no mechanism to control that in that case.
It all indicates that the event never gets set as you pointed out.
I have not checked for memory leaks either, mainly beacause the CALLBACK process function gets terminated , for now.
I think I need to go back to try CALLBACK on event instead of just plain CALLBACK function.
|
|
|
|
|
In the case you've provided, the WaitForSingleObject will wait forever (due to the INFINITE time specification), or until the event that's it's waiting on to be "set". Ideally, you should be changing the state of this event in another thread, and the wait will end.
Are you performing everything in the same thread? That's not how it's intended to work.
"Real men drive manual transmission" - Rajesh.
|
|
|
|
|
Yes, it is all done in the same thread.
This callback function starts the audio process and "monitors" the completion of the audio buffer which is set to output about 1 second of audio.
mmres = waveOutOpen(&hwout, WAVE_MAPPER, &wfme,
(DWORD) CallbackWaveOutProc, 0x12345, CALLBACK_FUNCTION);
The issue is that I want to utilize "loop" feature of this audio buffer and output the audio for more then 1 second. Without the "wait for event" the waveOutWrite returns immediately after the audio output starts, setting the WOM_DONE in the callback function.
Inserting the wait for event let the waveOutWrite generate the WOM_DONE AFTER the WHDR_DONE is asserted.
I did write simple wait loop to monitor this WHDR_DONE flag and it worked, but I thought I could use Windows event to do same. It does what I want, but I just do not understand how it does it.
Vaclav
|
|
|
|
|
I want to write program which would completely wipe out my hard disk and the data on the hard disk should not be recoverable once wiped. I want to implement this in c/c++.
|
|
|
|
|
|
I would guess that the only totally wipe would be using "format".
Definitely not in favor of the above link "toy program".
|
|
|
|
|
Step 1: Backup your drives.
This is meant as a humorous reminder. Seriously, don't run a single test before you are sure you have a working backup.
Soren Madsen
"When you don't know what you're doing it's best to do it quickly" - Jase #DuckDynasty
|
|
|
|
|
There's an open source project called DBAN that does this...
http://www.dban.org/[^]
http://en.wikipedia.org/wiki/Darik's_Boot_and_Nuke[^]
Since it's open source, you should be able to look through the source to see how they accomplish this (if you're trying to learn). If you're just trying to blast some old disks, you can just download it and use it, it works VERY WELL (be careful).
|
|
|
|
|
There is no way to make data completely unrecoverable. But using some shredding algorithms you can slow down the process of recovery of the shredded(deleted) data.
|
|
|
|
|
The following question is about how to handle assignment operators (& copy constructors)
in a hierarchy of polymorphic objects in order to be able to work with all kind of assignments & copy:
i.e. we would ideally like to work always with base class pointers, but also allow to use
directly derived class pointers.
In fact I do present two techniques to deal with this argument:
A) The first does make use of "virtual" assignment operators
and, as far as I know, should be the "standard" way to deal with this argument in C++,
but it has the drawback that as soon as your hierarchy is more than one level deep
it leads to a combinatorial explosion of assignment operators.
This technique I call "Polymorphism A" in the following.
B) The second technique does make use of an aux virtual copy method,
using this aux virtual copy method fewer assignment operators have to be defined,
but it has the drawback that you cannot call directly the base class assignment op. from derived ones.
This technique I call "Polymorphism B" in the following.
My question is more like an open discussion: i.e. I do ask what are your opinions on both techniques,
what drawbacks you may see in them, and, eventually, if you do know of a better way to solve the same problem.
In the sample code I give objects are relatively simple, but keep in mind that we would like
to apply those techniques to complicated objects where "deep" copies are to be used.
Let us see the code:
------- Polymorphism A - hierarchy --------------------
#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
using namespace std;
class CBase {
private:
CBase() { cout << "CBase() default ctor called" << endl;
_data = -1; _isvalid = false; };
public:
explicit CBase(const int data) { cout << "CBase(const int data) explicit ctor called" << endl;
_data = data; _isvalid = true; };
virtual ~CBase() { cout << "~CBase() dtor called" << endl; };
public:
CBase(const CBase& iOther) { cout << "CBase(const CBase& iOther) copy ctor called" << endl;
copyBase(iOther); };
virtual CBase& operator=(const CBase& iOther) { cout << "CBase& CBase::operator=(const CBase& iOther) assignment called" << endl;
if( this != &iOther ) {
copyBase(iOther); }
return *this;
};
private:
void copyBase(const CBase& iOther)
{ cout << "CBase::copyBase() copy called" << endl;
_data = iOther._data; _isvalid = iOther._isvalid; };
public: int getData() const { return _data; };
void setData(const int data) { _data = data; };
bool isValid() const { return _isvalid; };
void setValid(const bool isvalid) { _isvalid = isvalid; };
private:
int _data; bool _isvalid; };
class CDerivedA : public CBase {
private:
CDerivedA() : CBase((int) -1)
{ cout << "CDerivedA() default ctor called" << endl;
_dataA = -1.0; setValid(false); };
public:
explicit CDerivedA(const double dataA) : CBase((int) 0) { cout << "CDerivedA(const double dataA) explicit ctor called" << endl;
_dataA = dataA; };
virtual ~CDerivedA() { cout << "~CDerivedA() dtor called" << endl; };
public:
CDerivedA(const CDerivedA& iOther) : CBase(iOther) { cout << "CDerivedA(const CDerivedA& iOther) copy ctor called" << endl;
_dataA = iOther._dataA; };
virtual CDerivedA& operator=(const CDerivedA& iOther) { cout << "CDerivedA& CDerivedA::operator=(const CDerivedA& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::operator=(iOther);
_dataA = iOther._dataA; }
return *this;
};
CDerivedA(const CBase& iOther)
: CBase(iOther) { cout << "CDerivedA(const CBase& iOther) copy ctor called" << endl;
buildVirtualCopy(iOther);
};
virtual CBase& operator=(const CBase& iOther) { cout << "CBase& CDerivedA::operator=(const CBase& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::operator=(iOther);
buildVirtualCopy(iOther);
}
return *this;
};
private:
void buildVirtualCopy(const CBase& iOther)
{
cout << "CDerivedA::buildVirtualCopy copy ctor called" << endl;
const CDerivedA* pOther = dynamic_cast<const CDerivedA*> (&iOther);
if ( nullptr != pOther ) {
_dataA = pOther->_dataA;
}
else {
cout << "CDerivedA: explicit conversion from other type is forbidden" << endl;
setValid(false); }
};
public: double getDataA() const { return _dataA; };
void setDataA(const double dataA) { _dataA = dataA; };
private:
double _dataA; };
class CDerivedB : public CBase {
private:
CDerivedB() : CBase((int) -1)
{ cout << "CDerivedB() default ctor called" << endl;
_dataB = ""; setValid(false); };
public:
explicit CDerivedB(const string dataB) : CBase((int) 1) { cout << "CDerivedB(const string dataB) explicit ctor called" << endl;
_dataB = dataB; };
virtual ~CDerivedB() { cout << "~CDerivedB() dtor called" << endl; };
public:
CDerivedB(const CDerivedB& iOther) : CBase(iOther) { cout << "CDerivedB(const CDerivedB& iOther) copy ctor called" << endl;
_dataB = iOther._dataB; };
virtual CDerivedB& operator=(const CDerivedB& iOther) { cout << "CDerivedB& CDerivedB::operator=(const CDerivedB& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::operator=(iOther);
_dataB = iOther._dataB; }
return *this;
};
CDerivedB(const CBase& iOther)
: CBase(iOther) { cout << "CDerivedB(const CBase& iOther) copy ctor called" << endl;
buildVirtualCopy(iOther);
};
virtual CBase& operator=(const CBase& iOther) { cout << "CBase& CDerivedB::operator=(const CBase& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::operator=(iOther);
buildVirtualCopy(iOther);
}
return *this;
};
private:
void buildVirtualCopy(const CBase& iOther)
{
cout << "CDerivedB::buildVirtualCopy copy ctor called" << endl;
const CDerivedB* pOther = dynamic_cast<const CDerivedB*> (&iOther);
if ( nullptr != pOther ) {
_dataB = pOther->_dataB;
}
else {
const CDerivedA* pOtherA = dynamic_cast<const CDerivedA*> (&iOther);
if ( nullptr != pOtherA ) {
stringstream ss;
ss << setw(4) << pOtherA->getDataA();
_dataB = ss.str();
cout << "CDerivedB: explicit conversion from CDerivedA type" << endl;
}
else {
setValid(false); }
}
};
public: string getDataB() const { return _dataB; };
void setDataB(const string& dataB) { _dataB = dataB; };
private:
string _dataB; };
------- Polymorphism A - hierarchy --------------------
------- Polymorphism B - hierarchy --------------------
#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
using namespace std;
class CBase {
private:
CBase() { cout << "CBase() default ctor called" << endl;
_data = -1; _isvalid = false; };
public:
explicit CBase(const int data) { cout << "CBase(const int data) explicit ctor called" << endl;
_data = data; _isvalid = true; };
virtual ~CBase() { cout << "~CBase() dtor called" << endl; };
public:
CBase(const CBase& iOther) { cout << "CBase(const CBase& iOther) copy ctor called" << endl;
copyBase(iOther); };
CBase& operator=(const CBase& iOther) { cout << "CBase& CBase::operator=(const CBase& iOther) assignment called" << endl;
if( this != &iOther ) {
copyBase(iOther); buildVirtualCopy(iOther); }
return *this;
};
private:
void copyBase(const CBase& iOther)
{ cout << "CBase::copyBase() copy called" << endl;
_data = iOther._data; _isvalid = iOther._isvalid; };
protected:
virtual void buildVirtualCopy(const CBase& iOther) { cout << "CBase::buildVirtualCopy copy ctor called, it does nothing" << endl; };
public: int getData() const { return _data; };
void setData(const int data) { _data = data; };
bool isValid() const { return _isvalid; };
void setValid(const bool isvalid) { _isvalid = isvalid; };
private:
int _data; bool _isvalid; };
class CDerivedA : public CBase {
private:
CDerivedA() : CBase((int) -1)
{ cout << "CDerivedA() default ctor called" << endl;
_dataA = -1.0; setValid(false); };
public:
explicit CDerivedA(const double dataA) : CBase((int) 0) { cout << "CDerivedA(const double dataA) explicit ctor called" << endl;
_dataA = dataA; };
virtual ~CDerivedA() { cout << "~CDerivedA() dtor called" << endl; };
public:
CDerivedA(const CDerivedA& iOther) : CBase(iOther) { cout << "CDerivedA(const CDerivedA& iOther) copy ctor called" << endl;
_dataA = iOther._dataA; };
CDerivedA& operator=(const CDerivedA& iOther)
{ cout << "CDerivedA& CDerivedA::operator=(const CDerivedA& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::CBase(iOther); _dataA = iOther._dataA; }
return *this;
};
CDerivedA(const CBase& iOther)
: CBase(iOther) { cout << "CDerivedA(const CBase& iOther) copy ctor called" << endl;
buildVirtualCopy(iOther);
};
protected:
virtual void buildVirtualCopy(const CBase& iOther)
{
cout << "CDerivedA::buildVirtualCopy copy ctor called" << endl;
const CDerivedA* pOther = dynamic_cast<const CDerivedA*> (&iOther);
if ( nullptr != pOther ) {
_dataA = pOther->_dataA;
}
else {
cout << "CDerivedA: explicit conversion from other type is forbidden" << endl;
setValid(false); }
};
public: double getDataA() const { return _dataA; };
void setDataA(const double dataA) { _dataA = dataA; };
private:
double _dataA; };
class CDerivedB : public CBase {
private:
CDerivedB() : CBase((int) -1)
{ cout << "CDerivedB() default ctor called" << endl;
_dataB = ""; setValid(false); };
public:
explicit CDerivedB(const string dataB) : CBase((int) 1) { cout << "CDerivedB(const string dataB) explicit ctor called" << endl;
_dataB = dataB; };
virtual ~CDerivedB() { cout << "~CDerivedB() dtor called" << endl; };
public:
CDerivedB(const CDerivedB& iOther) : CBase(iOther) { cout << "CDerivedB(const CDerivedB& iOther) copy ctor called" << endl;
_dataB = iOther._dataB; };
CDerivedB& operator=(const CDerivedB& iOther)
{ cout << "CDerivedB& CDerivedB::operator=(const CDerivedB& iOther) assignment called" << endl;
if( this != &iOther ) {
this->CBase::CBase(iOther); _dataB = iOther._dataB; }
return *this;
};
CDerivedB(const CBase& iOther) : CBase(iOther) { cout << "CDerivedB(const CBase& iOther) copy ctor called" << endl;
buildVirtualCopy(iOther);
};
protected:
virtual void buildVirtualCopy(const CBase& iOther)
{
cout << "CDerivedB::buildVirtualCopy copy ctor called" << endl;
const CDerivedB* pOther = dynamic_cast<const CDerivedB*> (&iOther);
if ( nullptr != pOther ) {
_dataB = pOther->_dataB;
}
else {
const CDerivedA* pOtherA = dynamic_cast<const CDerivedA*> (&iOther);
if ( nullptr != pOtherA ) {
stringstream ss;
ss << setw(4) << pOtherA->getDataA();
_dataB = ss.str();
cout << "CDerivedB: explicit conversion from CDerivedA type" << endl;
}
else {
setValid(false); }
}
};
public: string getDataB() const { return _dataB; };
void setDataB(const string& dataB) { _dataB = dataB; };
private:
string _dataB; };
------- Polymorphism B - hierarchy --------------------
and a simple test program to test both of them:
------- test program for both hierarchies -------------
int _tmain(int argc, _TCHAR* argv[])
{
cout << "Program starts..." << endl;
cout << endl;
{
CDerivedA* pA0 = new CDerivedA((double) 1.0);
CDerivedA* pA1 = new CDerivedA((double) 2.0);
CDerivedB* pB0 = new CDerivedB(string("This is B1"));
CDerivedB* pB1 = new CDerivedB(string("This is B2"));
cout << endl;
CBase* p00 = nullptr;
CBase* p01 = nullptr;
cout << "Assignment via base pointers of type A objects" << endl;
p00 = pA0;
p01 = pA1;
*p00 = *p01;
cout << "pA0 dataA = " << pA0->getDataA() << endl;
cout << "pA1 dataA = " << pA1->getDataA() << endl;
cout << endl;
p00 = nullptr;
p01 = nullptr;
cout << "Assignment via base pointers of type B objects" << endl;
p00 = pB0;
p01 = pB1;
*p00 = *p01;
cout << "pB0 dataB = " << pB0->getDataB() << endl;
cout << "pB1 dataB = " << pB1->getDataB() << endl;
cout << endl;
p00 = nullptr;
p01 = nullptr;
cout << "Cross Assignment via base pointers from type B objects to type A is forbidden" << endl;
p00 = pA0;
p01 = pB0;
cout << "p00 is pointing to pA0 " << endl;
*p00 = *p01;
cout << "p00 is valid = " << p00->isValid() << endl;
cout << endl;
p00 = nullptr;
p01 = nullptr;
cout << "Cross Assignment via base pointers from type A objects to type B" << endl;
cout << "is allowed by custom conversion... " << endl;
p00 = pB1;
p01 = pA1;
cout << "p00 is pointing to pB1 " << endl;
*p00 = *p01;
cout << "p00 is valid = " << p00->isValid() << endl;
cout << "p00 --> pB1 dataB = " << pB1->getDataB() << endl;
cout << endl;
p00 = nullptr;
p01 = nullptr;
delete pA0;
delete pA1;
delete pB0;
delete pB1;
cout << endl;
}
{
CDerivedA* pA0 = new CDerivedA((double) 1.0);
CDerivedA* pA1 = new CDerivedA((double) 2.0);
CDerivedB* pB0 = new CDerivedB(string("This is B1"));
CDerivedB* pB1 = new CDerivedB(string("This is B2"));
cout << endl;
cout << "Assignment via pointers of type A objects" << endl;
*pA0 = *pA1;
cout << "pA0 dataA = " << pA0->getDataA() << endl;
cout << "pA1 dataA = " << pA1->getDataA() << endl;
cout << endl;
cout << "Assignment via pointers of type B objects" << endl;
*pB0 = *pB1;
cout << "pB0 dataB = " << pB0->getDataB() << endl;
cout << "pB1 dataB = " << pB1->getDataB() << endl;
cout << endl;
delete pA0;
delete pA1;
delete pB0;
delete pB1;
cout << endl;
}
{
cout << "Base class Assignment just works." << endl;
CBase* p00 = nullptr;
CBase* p01 = nullptr;
p00 = new CBase((int) 10);
p01 = new CBase((int) 11);
*p00 = *p01;
cout << "p00 is valid = " << p00->isValid() << endl;
cout << "p00 data = " << p00->getData() << endl;
cout << "p01 is valid = " << p01->isValid() << endl;
cout << "p01 data = " << p01->getData() << endl;
cout << endl;
delete p00;
cout << endl;
cout << "Base class copy ctor just works." << endl;
p00 = new CBase(*p01);
cout << "p00 is valid = " << p00->isValid() << endl;
cout << "p00 data = " << p00->getData() << endl;
delete p00;
delete p01;
cout << endl;
}
{
cout << "Copy ctor via pointers of type A objects" << endl;
CDerivedA* pA1 = new CDerivedA((double) 2.0);
cout << endl;
CDerivedA* pA2 = new CDerivedA(*pA1);
cout << "pA1 dataA = " << pA1->getDataA() << endl;
cout << "pA2 dataA = " << pA2->getDataA() << endl;
delete pA1;
delete pA2;
cout << endl;
cout << "Copy ctor via pointers of type B objects" << endl;
CDerivedB* pB1 = new CDerivedB(string("This is B2"));
cout << endl;
CDerivedB* pB2 = new CDerivedB(*pB1);
cout << "pB1 dataB = " << pB1->getDataB() << endl;
cout << "pB2 dataB = " << pB2->getDataB() << endl;
delete pB1;
delete pB2;
cout << endl;
cout << "Copy ctor via base pointers of type A,B objects" << endl;
CBase* p00 = new CDerivedA((double) 1.0);
CBase* p01 = new CDerivedB(string("This is B1"));
cout << endl;
cout << "A from A via base" << endl;
CDerivedA* pA3 = new CDerivedA(*p00);
cout << endl;
cout << "base from A (slicing)" << endl;
CBase* pA4 = new CBase(*p00); cout << endl;
cout << "B from B via base" << endl;
CDerivedB* pB3 = new CDerivedB(*p01);
cout << endl;
cout << "base from B (slicing)" << endl;
CBase* pB4 = new CBase(*p01); cout << endl;
cout << "A from B via base" << endl;
CDerivedA* pA5 = new CDerivedA(*p01);
cout << endl;
cout << "B from A via base" << endl;
CDerivedB* pB5 = new CDerivedB(*p00);
cout << endl;
delete pA3;
delete pA4;
delete pA5;
delete pB3;
delete pB4;
delete pB5;
delete p00;
delete p01;
cout << endl;
}
int k = getchar();
return 0;
}
------- test program for both hierarchies -------------
Thanks in advance for any suggestion about why you would go with one instead of the other
(or, if eventually you do know a better idiomatic solution).
Federico
|
|
|
|
|
That looks like a shed load of code just to implement copying and assignment. Are you sure that copying objects of arbitrary types is both necessary to your design and won't turn into a complete millstone around your development team's neck? They might not thank you when they have to grind that lot out again to implement a new class? I'm also wincing at how the assignment operators are written - the canonical way you write an assignment operator in C++ is to use a copy and swap.
So... What would I suggest? Firstly go back to your design and see if it can be reworked to use a set of relatively simple principles:
- value types have no polymorphic behaviour and are copy constructable and assignable if appropriate. Use copy and swap to write the assignment operator for a value type
- polymorphic types are accessed through interfaces. Don't assign or copy the objects themselves, reference them through pointers or references to the interfaces they implement. The only place that knows the concrete type of a polymorphic type is the lump of code that creates the object
- don't use implementation inheritance. Containment gives far less headaches
- minimise manual memory management wherever possible. Use parameterise from above (PFA) and objects created on the stack wherever possible. If you write a delete statement pinch yourself and look at using std::unique_ptr or std::shared_ptr instead. RAII is your friend
- make everything exception safe but don't handle exceptions in too many places. One try/catch set in a function
If there's still a need to deep copy objects through pointers to arbitrary base classes then consider implementing a clonable interface. Never slice objects - once you lop off the context you can never get it back.
|
|
|
|
|
Thanks Aescleal,
all the techniques you suggest are fine, but my point was more on the discussion
of the copy ctor and assignment op. themselves: it is clear that if I make them
private, or if I just use the compiler generated ones for POD types, there will
be no worry.
By the way what do you mean exactly by "copy and swap" ? Do you mean this ? :
Object& operator = (const Object& other)
{
Object(other).swap(*this);
return *this;
}
(How do you ensure no self assignment in this case ?, by forwarding to std::swap ?)
My point anyway was about how to do in the correct way when I've a hierarchy,
I've deep copies, I've to be able to use base class pointers or derived pointers:
i.e. in the most general case.
In this general case it seems to me that you're forced to use one of the given approaches,
and that you shall handle all cases of copy ctor and assignment ops explicitly
(derived from derived, derived from base, base from derived, base from base)
maybe just disallowing some of them.
Just to be clear, my point is the following:
CBase* pbase0 = new CDerived(...);
CBase* pbase1 = new CDerived(...);
*pbase0 = *pbase1
Bye
Federico
modified 22-Oct-13 4:44am.
|
|
|
|
|
Generally: Deep hierarchies (i.e. anything more than inheriting an interface) are bad news. Implementation inheritance is the strongest coupling there is and you'll end up with fragile logical designs (you'll spend ages trying to work out what goes where in your class taxonomy and find you have to shuffle a lot of members around) and long build times (when you shuffle you'll have to rebuild the world). If you stick to parameterise from above and interface inheritance you won't have to copy objects, just references and the whole question becomes moot.
Copy and swap is:
T &T::operator=( const T &t )
{
T temp( t );
swap( temp );
return *this;
}
where swap is non-throwing. You get exception safety for free and if you use the PIMPL idiom and lean on std::unique_ptr it's pretty trivial to implement.
|
|
|
|
|