3 ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_ctor, dtor, and assignment (iv).pdf ·...

25
Ctor, Dtor, and Assignment,The Practice of Programming, CSIE@NTNU, 2010 88 Exercise Write a base class CPlayer and three classes CAmazon, CPaladin, and CSorceress derived from CPlayer to make the left program show the following result: I am an amazon! I am a paladin! I am a sorceress!

Upload: others

Post on 07-Mar-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201088

Exercise

Write a base class CPlayer andthree classes

CAmazon, CPaladin, and CSorceress

derived from CPlayer to make the left

program show the following result:

I am an amazon!I am a paladin!I am a sorceress!

Page 2: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201089

Exercise

Page 3: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201090

Exercise

I am an amazon!I am a paladin!I am a sorceress!

Page 4: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201091

Exercise

We have 0 amazons, 0 paladins, and 0 sorceress.We have 1 amazons, 1 paladins, and 1 sorceress.We have 2 amazons, 3 paladins, and 1 sorceress.We have 1 amazons, 1 paladins, and 1 sorceress.We have 0 amazons, 1 paladins, and 1 sorceress.

Page 5: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201092

Declare Destructors Virtual inPolymorphic Base Classes.

int main() {CPlayer *p[3] = {new CAmazon,

new CPaladin,new CSorceress};

for (int i=0; i<3; ++i) {p[i]->Display();

}

// ...

for (int i=0; i<3; ++i) {delete p[i];

}}

class CPlayer{public:

CPlayer() { ... }~CPlayer() { ... }virtual void Display() = 0;

// ...};class CAmazon : public CPlayer {public:

virtual void Display() { }// ...};class CPaladin : public CPlayer {public:

virtual void Display() { }// ...};class CSorceress : public CPlayer {

virtual void Display() { }// ...};

It is an undefined behavior to delete aderived class object through a baseclass pointer with non-virtual destructor.

Page 6: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201093

Declare Destructors Virtual inPolymorphic Base Classes.Declare the destructor virtual when your class

contains at least one virtual member function.class CPlayer {public:

CPlayer() { ... }virtual ~CPlayer() { ... }virtual void Display() = 0;

// ...};// ...

int main() {CPlayer *p[3] = {new CAmazon,

new CPaladin,new CSorceress};

// ...for (int i=0; i<3; ++i) {

delete p[i];}

}Now its behavior is correct

Page 7: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201094

Declare Destructors Virtual inPolymorphic Base Classes. For those classes that are not designed as base classes. Write

the document clearly to tell the clients not to inherit from it.

class SpecialString: public std::string{// ...};int main(){

SpecialString *pss = new SpecialString(“Ah...”);std::string *ps;// ...ps = pss;// ...delete ps;

}

std::string is not designed to be a baseclass. You may use composition rather thaninheritance.

•A simple “derivation prohibition strategy”is to make all constructors private and provide a publicstatic method to instantiate the object (like a factory function).•Another strategy resorts to friend and virtual inheritance.

Page 8: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201098

Declare Destructors Virtual inPolymorphic Base Classes. For those base classes that are not designed for polymorphic

use (they do not have virtual member functions),make their destructors protected to avoid misuse of polymorphism non-virtual to avoid unnecessary increase of object size

int main() {cout << sizeof(CPoint) << ' ' << sizeof(CLargePoint);return 0;

}

class CLargePoint {public:

virtual ~CLargePoint() {}private:

int x, y;};

class CPoint {protected:

~CPoint() {}private:

int x, y;};

The size of CLargePoint objects gets larger since the invocation of virtual member functionsis usually achieved by a virtual table pointer (vptr) to a virtual table of virtual member functions.

8 12

Page 9: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201099

Never Call Virtual Functions duringConstruction and Destruction.

class Transaction {public:

Transaction();virtual void logTransaction() const = 0;

// ...};Transaction::Transaction(){

// ...logTransaction();

}

class BuyTransaction: public Transaction {public:

virtual void logTransaction() const;};class SellTransaction: public Transaction {public:

virtual void logTransaction() const;};

What’s the problem here?

Page 10: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010100

Never Call Virtual Functions duringConstruction and Destruction.Construction of a derived class object

Step1. Calling the constructors of base class(es) followingthe order in which they appear in the class derivation list.

Step2. Calling the constructors for non-static member classobjects following the order in which they are declared.

Step3. Entering the computation phase of the constructor ofthe derived class.

class Derived: public Base1, public Base2 {public:

Derived() {// computation phase

}private:

Component1 c1;Component2 c2;

};

Steps of Construction

Base1()Base2()Component1()Component2()// computation phase

Page 11: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010101

Never Call Virtual Functions duringConstruction and Destruction. During execution of constructors of the base class, virtual

functions of the derived class will not be invoked. Rationale:

Calling virtual functions of the derived class before the derivedpart is initialized is not reasonable.

Standard:During construction of base part, the type of object is the baseclass rather than the derived class.class Transaction {public:

Transaction();virtual void logTransaction() const = 0;

// ...};Transaction::Transaction() {

// ...logTransaction();

}

Page 12: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010102

Never Call Virtual Functions duringConstruction and Destruction.Destruction of a derived class object

The execution follows the reverse order of construction.

class Derived: public Base1, public Base2 {public:

Derived() {// computation phase

}private:

Component1 c1;Component2 c2;

};

Steps of Destruction

// computation phase~Component2()~Component1()~Base2()~Base1()

Page 13: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010103

Never Call Virtual Functions duringConstruction and Destruction. During execution of destructors of the base class, virtual

functions of the derived class will not be invoked. Rationale:

Calling virtual functions of the derived class after the derivedpart is destroyed is not reasonable.

Standard:During destruction of base part, the type of object is the baseclass rather than the derived class.

Page 14: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010104

Never Call Virtual Functions duringConstruction and Destruction.Can the compiler/linker help us?

In some simple cases, they might be able to detect it.

class Transaction {public:

Transaction();virtual void logTransaction()

const = 0;// ...};Transaction::Transaction(){

// ...logTransaction();

}

class BuyTransaction: public Transaction

{public:virtual void logTransaction() const{}

};class SellTransaction

: public Transaction{public:virtual void logTransaction() const{}

};

int main(){

BuyTransaction bTrans;return 0;

} DevC++4980:In constructor `Transaction::Transaction()': abstract virtual `virtual voidTransaction::logTransaction() const' called from constructor

// compilation warning or linkage error!

Page 15: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010105

Never Call Virtual Functions duringConstruction and Destruction. But in more complex cases, compiler/linker can not

detect the problem.class Transaction {public:

Transaction();virtual void logTransaction()

const = 0;void legal() { trick(); }

private:void trick(){ logTransaction(); }

};Transaction::Transaction() {

trick();}

class BuyTransaction: public Transaction

{public:virtual void logTransaction() const{}

};class SellTransaction

: public Transaction{public:virtual void logTransaction() const{}

};

int main(){

BuyTransaction bTrans;bTrans.legal();return 0;

}

// no warning or error!The program will terminate with the following message:pure virtual method calledThis application has requested the Runtime to terminate it in an unusual way.Please contact the application's support team for more information.

Page 16: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010106

Never Call Virtual Functions duringConstruction and Destruction. In the worst case, the program just goes “smoothly”

with potential errors.class Transaction {public:

Transaction();virtual void logTransaction()const {

// ...}

private:};Transaction::Transaction() {

logTransaction();}

class BuyTransaction: public Transaction

{public:virtual void logTransaction() const{}

};class SellTransaction

: public Transaction{public:virtual void logTransaction() const{}

};

int main(){

BuyTransaction bTrans;return 0;

}

// no warning or error!

Page 17: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010107

Never Call Virtual Functions duringConstruction and Destruction. Solutions to post-construction

(immediately calling a virtual function after constructing theentire object)

1. Pass the duty: Just document that user code must do it.2. Post-initialize lazily: Do it during the first call of a member

function. A boolean flag in the base class tells whether ornot post-construction has taken place yet.

3. Pass information from derived class to base class.4. Use a factory function: This way, you can easily force a

mandatory invocation of a post-constructor function.

Page 18: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010108

Never Call Virtual Functions duringConstruction and Destruction. Solutions to post-construction: Post-initialize lazily

class Transaction {public:

Transaction():isPostInit_(false) {}virtual void logTransaction() const { ... }

protected:bool isPostInit_;void PostInit() {

if (!isPostInit_) { logTransaction(); isPostInit_ = true; }}

};

class BuyTransaction: public Transaction {public:

virtual void logTransaction() const {}void AnyMemberFunc() {

PostInit();// ...

}// ...};

Page 19: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010109

Never Call Virtual Functions duringConstruction and Destruction. Solutions to post-construction: Pass informationclass Transaction {public:

explicit Transaction(const std::string & logInfo);void logTransaction(const std::string &logInfo) const; // non-virtual

private:};Transaction::Transaction() {const std::string &logInfo) {

// ...logTransaction(logInfo);

}

class BuyTransaction: public Transaction {public:

BuyTransaction( parameters ): Transaction( createLogString(parameters) ) { ... }

private:static std::string createLogString( parameters );

};

FAQ1: Why explicit?

FAQ2: Why static?

FAQ1: To prohibit implicit conversion from std::string to Transaction.FAQ2: To avoid using uninitialized data members in the BuyTransaction object.

Page 20: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010110

Never Call Virtual Functions duringConstruction and Destruction. Solutions to post-construction: Use a factory function

class Transaction {public:

Transaction() {}virtual void logTransaction()

const {} // still virtual

template<class T>static T * Create() {

T *p = new T;p->logTransaction();return p;

}// ...};

class BuyTransaction: public Transaction

{public:virtual void logTransaction() const{}

};

class SellTransaction: public Transaction

{public:virtual void logTransaction() const{}

};

int main() {BuyTransaction *p = BuyTransaction::Create<BuyTransaction>();return 0;

}

Constraints: (1) The derived class must not expose any constructor.(2) Construction can be achieved only through new operation.

Page 21: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010111

Copy and Destroy Consistently.

What you create, also clean up:If you define any of the copy constructor (CC), copy assignmentoperator (CA), or destructor (D), you might need to define one orboth of the others.

If you write/disable either CC or CA, you probably need to do thesame for the other since they should have similar effects.

If you explicitly write CC and CA (usu. to allocate or duplicate someresource), you need to deallocate it in D.

If you explicitly write D to manually release a resource, youprobably need to do duplication carefully or to disable copying.

Prefer compiler-generated special members; only these can beclassified as “trivial,”and at least one major STL vendor heavilyoptimizes for classes having trivial special members.

Page 22: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010112

Avoid Slicing.

Is there something wrong?

class Base { ... };class Derived : public Base { ... };

void StrangeFunc(Base obj) { ... }

void PolyFunc(Base &obj) {StrangeFunc(obj);

// ...}int main(){

Derived d;PolyFunc(d);

}

The programmer intends to manipulate Base and Base-derived objects polymorphically.However, when StrangeFunc() is invoked, the object passed in is only the sliced Basepart of the Derived object.

Page 23: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010113

Avoid Slicing.

In base classes, consider disabling the copyingfunctions.

class Base {// ...protected:

Base(const Base&) { ... }};class Derived : public Base {// ...protected:

Derived(const Derived &rhs):Base(rhs) { ... }};

void StrangeFunc(Base obj) { ... }

int main() {Derived d;StrangeFunc(d);

}// Compilation error

Page 24: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010114

Avoid Slicing.

Instead, provide a virtual clone function forpolymorphic copying.

class Base {public:

virtual Base* Clone() const = 0;// ...protected:

Base(const Base&) { ... }};class Derived : public Base {public:

virtual Derived* Clone() const { return new Derived(*this); }// ...protected:

Derived(const Derived &rhs):Base(rhs) { ... }};

There is still one problem, a further-derived class in the hierarchy can still forget toimplement Clone().

Page 25: 3 Ctor, dtor, and assignmentweb.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (IV).pdf · “Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010 94

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010115

Avoid Slicing.

We can apply the NonVirtual Interface (NVI) patternand put a valuable assertion.

class Base {public:Base* Clone() const {

Base* p = DoClone();assert( typeid(*p) == typeid(*this)

&& “DoClone incorrect!” );return p;

}// ...protected:

Base(const Base&) { ... }private:

virtual Base* DoClone() const = 0;};

class Derived : public Base{private:

virtual Derived* DoClone() const{

return new Derived(*this);}

};

class DerDer : public Derived{

// Forget to provide DoClone()};

int main() {DerDer dd;Base *p1 = &dd, *p2;p2 = p1->Clone();

} // Causes run-time due to violation of assertion.