问题聚焦: 不要在构造函数和析构函数中调用virtual函数,因为这样的调用不会带来你预想的结果. 让我先来看一下在构造函数里调用一个virtual函数会发生什么结果 Demo class Transaction { public: Transaction(); ; }; Transaction::Transaction() { logTransaction(); } //void Transaction::logTransaction() const //第一次编译时,注释掉该段代码 //{…
#include <iostream> class cx { public: virtual void func() { std::cout << "func" << std::endl; } cx() { func(); //构造函数中调用虚函数,语法上OK,效果上不对,因为当对象由子类进入基类构造时是基类类型的 //不管如何调用,总只能调用到基类的虚函数,无法调用到子类的虚函数,见下面测试 } }; class cb : public cx {…
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为方便采用书上的例子,先提出问题,在说解决方案. 1 问题 1: class Transaction{ 2: public: 3: Transaction(); 4: virtual void LogTransaction() const = 0 ; 5: ... 6: }; 7:  8: Transaction::Transaction() //Base cl…
在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层).…
看过C++对象模型的话就可以知道,在构造基类时,完整的vtable没有建立起来(表项没有被相应的子类函数替换),因而无法调用到子类的函数(即构造函数中的virtual函数是本类里的方法,不是virtual的).书中也说即使调用了,因为构造函数的调用顺序,父类在构造时子类的成员还没有初始化可能,此时调用virtual函数无疑会造成混乱. 类似的关于析构过程,是一个子类先执行然后再父类执行的过程,如果在父类中调用virtual函数那么可能涉及到的子类数据已经被释放或者重置了,应该是出于这个考虑吧.…
  1.当在一个子类当中调用构造函数,其父类构造函数肯定先被调用.如果此时父类构造函数中有一个virtual函数,子类当中也有,肯定执行父类当中的virtual函数,而此时子类当中的成员变量并未被初始化,所以无法调用子类与之对应的函数.即为指向虚函数表的指针vptr没被初始化又怎么去调用派生类的virtual函数呢?析构函数也相同,派生类先于基类被析构,又如何去找派生类相应的虚函数? 2.做法:将子类的某个函数改为non-virtual,然后在子类构造函数中传递参数给父类函数.然后父类的构造函数…
在构造和析构执行期间不要调用virtual函数,因为这类调用从不会下降至derived class(比起当前执行构造函数和析构函数) 如果在base class 构造函数或者析构函数调用virtual,derived class构造时会先构造base class,则base class中的virtual实际调用是base class的; 第一种解释:derived class类先执行构造base class部分,然而在base class构造过程中,derived class部分是为初始化的,如…
在base class构造期间,virtual函数不是virtual函数. 构造函数.析构函数中不要调用virtual函数.…
面向对象编程中,函数.方法.类的构造函数是三种不同的概念. JS中,它们只是单个构造对象的三种不同的使用模式. 三种不同的使用模式 函数调用 function hello(username){ return 'hello,'+username; } hello('world');//"hello,world" 函数的表现与行为一致,调用hello函数并将给定的实参绑定到username形参. 方法调用 js中的方法,是指对象的属性恰好是函数而已. var obj={ hello:fun…
如下是一个股票交易的例子: class Transaction // 交易的基类 { public: Transaction(); ; // 用于记录交易日志 }; Transaction::Transaction() { logTransaction(); // 调用虚函数 } class BuyTransaction : public Transaction // 买进股票 { virtual void logTransaction() const; }; void BuyTransacti…
如不使用自动生成函数要明确拒绝 对于一个类,如果你没有声明,c++会自动生成一个构造函数,一个析构函数,一个copy构造函数和一个copy assignment操作符. class Empty { public: Empty() { ... } // default constructor Empty(const Empty& rhs) { ... } // copy constructor ~Empty() { ... } // destructor — see below // for wh…
游戏中的人物伤害值计算问题. (一)方法(1):一般来讲能够使用虚函数的方法: class GameCharacter { public: virtual int healthValue() const; //返回人物的体力值,派生类能够做出改动 ... }; 这确实是一个显而易见的设计选择.但由于这种设计过于显而易见,可能不会对其他可选方法给予足够的关注.我们来考虑一些处理这个问题的其他方法. (二)方法(2):使用NVI方法,在基类中使用一个公有的普通函数调用私有的虚函数. class Ga…
1.函数调用 Function绝对是JavaScript中的重中之重.在JavaScript中,Function承担了procedures, methods, constructors甚至是classes以及modules的功能. 在面向对象程序设计中,functions,methods以及class constructor往往是三件不同的事情,由不同的语法来实现.但是在JavaScript中,这三个概念都由function来实现,通过三种不同的模式. 最简单的使用模式就是function 调用…
NOTE:在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)…
不该在构造函数和析构函数期间调用virtual函数,这一点是C++与jave/C#不同的地方之一. 假设有一个class继承体系,用来模拟股市交易如买进.卖出的订单等等.这样的交易一定要经过审计,所以每当创建一个交易对象,在审计日志中也需要创建一笔适当记录. 正确的做法是在基类Transaction内将logTransaction函数改为non-virtual,然后要求派生类构造函数传递必要信息给基类Transaction的构造函数,这样那个构造函数便可安全地调用non-virtual logT…
//构造函数调用规则 #include <iostream> using namespace std; //1.创建一个类,C++编译器会给每个类添加至少3个函数 //默认构造(空实现) //析构函数(空实现) //拷贝函数(值拷贝) //2.如果我们写了有参构造函数 编译器就不会提供默认构造函数 但是会提供拷贝构造函数 //3.如果我们写了拷贝函数 编译器就不再提供 默认 有参 构造函数 class Person { public: Person() //默认构造函数 { cout <…
1 //拷贝构造函数调用时机 2 3 4 #include <iostream> 5 using namespace std; 6 7 //1.使用一个已经创建完毕的对象来初始化一个新对象 8 9 10 //2.值传递的方式给函数参数传值 11 12 13 //3.值方式返回局部对象 14 15 16 class Person 17 { 18 public: 19 Person() 20 { 21 cout << "Person默认构造函数调用" <<…
virtual函数的替代方案包括NVI手法及Strategy设计模式的多种手法.NVI手法自身是一个特殊形式的Template Method设计模式. 将机能从成员函数移到class外部函数,带来的一个缺点是,非成员函数无法访问class的non-public成员. tr1::function对象的行为就想一般函数指针.这样的对象可接纳“与给定之目标签名式(target signature)兼容”的所有可调用物(callable entities).…
绝不重新定义继承来的缺省值 首先明确下,虚函数是动态绑定,缺省参数值是静态绑定 // a class for geometric shapes class Shape { public: enum ShapeColor { Red, Green, Blue }; // all shapes must offer a function to draw themselves ; ... }; class Rectangle: public Shape { public: // notice the…
#include <iostream> #include <cstdlib> using namespace std; class Pen { public: ) { cout<<"write with color:"<<color<<endl; } }; class Pencil : public Pen{ public: ) { cout<<"write with color:"<&l…
//条款07:为多态基类声明virtual析构函数 // 1.若基类的析构函数不定义为虚函数,由于基类的指针或引用可以指向派生类的对象,则在删除基类对象的时候可能会出错,导致破坏数据结构. // 2.如果一个类不含有虚析构函数,那么通常表示它并不希望其本身成为一个基类. // 3.不要为普通的类声明一个虚析构函数.这是因为C++为了实现虚函数,会建立一个由函数指针构成的数组,称为虚函数表,导致类的对象必须携带额外信息来决定运行期间哪个虚函数会被调用,这个额外信息通常由一个指针组成,此指针指向虚函…
先看一个例子: #include <iostream> using namespace std; class A{ public: A() { show(); } virtual void show(){ cout<<"in A"<<endl; } virtual ~A(){ show(); } }; class B:public A{ public: B() { show(); } void show(){ cout<<"in…
条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函数时,编译器会给我们构造默认的. 当成员变量里有const对象或引用类型时,编译器会不能合成默认的拷贝赋值函数:当一个基类把它的拷贝赋值函数定义为private时,它的派生类也不无生成默认的拷贝赋值函数,因为它无法完成基类成份的赋值. 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 将拷贝构…
05:了解C++默默编写并调用哪些函数 1:一个空类,如果你自己没声明,编译器就会为它声明(编译器版本的)一个copy构造函数.一个copy assignment操作符和一个析构函数.此外如果你没有声明任何构造函数,编译器也会为你声明一个default构造函数.所有这些函数都是public且inline的. 2:只有当这些函数被调用时,它们才会被编译器创建出来. 3:编译器生成的default构造函数和析构函数主要是给编译器一个地方用来放置“藏身幕后”的代码,比如用base classes和no…
http://blog.csdn.net/freeboy1015/article/details/7635012 为什么内联函数,构造函数,静态成员函数不能为virtual函数? 1> 内联函数 内联函数是在编译时期展开,而虚函数的特性是运行时才动态联编,所以两者矛盾,不能定义内联函数为虚函数. 2> 构造函数 构造函数用来创建一个新的对象,而虚函数的运行是建立在对象的基础上,在构造函数执行时,对象尚未形成,所以不能将构造函数定义为虚函数. 3> 静态成员函数 静态成员函数属于一个类而非…
详情见<Effective C++>item35 1.使用non-virtual interface(NVI)手法,这是Template Method设计模式的一种特殊形式. 它以public non-virtual成员函数包裹较低访问性(private 或 protected)的virtual函数. 2.strategy设计模式 a.将virtual 函数替换为“函数指针成员变量” b.以tr1::function成员变量替换virtual函数,因而允许使用任何可调用物搭配一个兼容于需求的签…
当你每次看到C++类中声明一个virtual函数,特别是看到了一个virtual的虚构函数.你知道它的意思吗?你肯定会毫不犹豫的回答:不就是多态么...在运行时确定具体的行为么...完全正确,但这里我要讲的不只是这些东西. 有些类需要虚函数,有些不需要虚函数.这是为什么,一般你看到的类如果有一个虚析构函数,那么这个类中应该会有至少一个是虚函数的..这是为什么呢??如果我们类中没有用其他虚函数的话,你创建了这个也是多余的,而且会增加类对象的大小..说这些纯理论的东西,也许大家不知所云..下面我就给…
C++的全局类和静态类的构造函数是在main函数之前调用的.但是,不同的类的构造函数以什么顺序调用呢? 对于g++编译器来说,这个顺序是由链接时,文件顺序决定的. 我们用一个例子来说明这一点. 我们有3个文件:t1.h, t1.cpp和tt1.cpp,内容分别是 t.h #ifndef T_H #define T_H #include <stdio.h> class A { public: A(); }; class B { public: B(){ a_ = NULL; } void set…
class A { int a; int b; int c; public: A(int aa, int bb) : a(aa), b(bb),c(0) { cout << "aa bb" << endl; } A(int aa, int bb, int cc); }; 上面类中,已经有一个构造函数,形参有两个,我们又重载一个有3个形参的构造函数,为了减少代码量,就想着让3个参数的构造函数调用2个参数的构造函数,然后在执行一些自己的代码,这就如同派生类先调用基类…
构造函数调用构造函数是会问题的. 外层函数返回的内存, 与被调用的构造函数返回的内存并不是一个内存. 错误示例代码如下: msg_log(const char *name, const char* thread_name, const char *cfg_file, int type = STREAM, int level = MSG_ERROR) : _name(name), _thread_name(thread_name), _level(level), _type(type), logf…