如果类的内部没有专门创建实例的代码,则是无法创建任何实例的 如果父类构造函数设置成了私有的,则子类无法编译,因为在初始化子类时会先执行父类的构造 class A{ public: private: A(int ){ } }; class B:public A{ public: int x; }; int main( ) { B b; b.x = 0; return 0; } 输出:
Start prog.cc:19:7: error: call to implicitly-deleted default constructor of 'B' B b; ^ prog.cc:13:9: note: default constructor of 'B' is implicitly deleted because base class 'A' has an inaccessible default constructor class B:public A{ ^ 1 error generated. 1 Finish
一、只能在堆上 方法:将析构函数设置为私有
原因:C++ 是静态绑定语言,编译器管理栈上对象的生命周期,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性。若析构函数不可访问,则不能在栈上创建对象
class Test { public: void printT(){ cout << "printT" << endl; } void freeT(){ delete this; } private: ~Test(){ cout << "~Test()" << endl; } }; int main( ) { // 不能在栈上创建对象 //Test t; // prog.cc:25:10: error: variable of type 'Test' has private destructor // 只能在堆上创建对象 Test *t = new Test; t->printT(); // 销毁对象 t->freeT(); return 0; } 输出:
Start printT ~Test() 0 Finish 二、只能在栈上 方法:将 new 和 delete 重载为私有...
抽象类:含有纯虚函数的类,不能实例化对象 接口类:仅含有纯虚函数的抽象类 聚合类:用户可以直接访问其成员,并且具有特殊的初始化语法形式。满足如下特点:
1)所有成员都是 public,没有私有和受保护的非静态成员;
2)没有定义任何构造函数;
3)没有类内初始化;
4)没有基类,也没有 virtual 函数 // 接口类 class A { virtual void printA() = 0; // 纯虚函数 }; // 抽象类 class AA:public A { public: // 覆写接口类的纯虚函数 void printA() override { cout << "class AA printA()" << endl; } virtual void printAA() = 0; }; // 可实例化的类 class B:public AA { public: // 覆写父类(抽象类)的纯虚函数 void printAA() override { cout << "class B printAA()" << endl; } void printB() { cout << "printB()" << endl; } }; // 聚合类 class C { public: int x; int y; void print(){ cc(); } private: void cc(){ cout << "x = " << x << ", y = " << y << ", z = " << z << endl; } static int z; }; int C::z = 0; class D { public: int a; int b; C c; void print(){ cout << "a = " << a << ", b = " << b << endl; c....
虚继承和虚基类 参考
在C++中,在定义公共基类A的派生类B、C…的时候,如果在继承方式前使用关键字virtual对继承方式限定,这样的继承方式就是虚拟继承,公共基类A成为虚基类。这样,在具有公共基类的、使用了虚拟继承方式的多个派生类B、C…的公共派生类D中,该基类A的成员就只有一份拷贝 一个类有多个基类,这样的继承关系称为多继承。在多继承的情况下,如果不同基类的成员名称相同,匹配度相同, 则会造成二义性。为了避免多继承产生的二义性,在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。 会在虚继承的类中生成一个指向虚基类的指针 {vbptr} 会在内存中生成一个虚基类表 D::$vbtable@B@ 微软的Visual Studio提供给用户显示C++对象在内存中的布局的选项
cl [filename].cpp /d1 reportSingleClassLayout[className]
一般继承:
class A { public: int dataA; }; class B:public A { public: int dataB; }; class C:public A { public: int dataC; }; class D : public B, public C { public: int dataD; }; 输出:
class D size(20): +--- 0 | +--- (base class B) 0 | | +--- (base class A) 0 | | | dataA | | +--- 4 | | dataB | +--- 8 | +--- (base class C) 8 | | +--- (base class A) 8 | | | dataA | | +--- 12 | | dataC | +--- 16 | dataD +--- 调用:...
1. C++ 多态分类及实现 重载多态(Ad-hoc Polymorphism,编译期):函数重载、运算符重载(静态多态、静态编译) 子类多态(Subtype Polymorphism,运行期):虚函数(动态多态、动态编译) 参数多态(Parametric Polymorphism,编译期):类模板(泛型)、函数模板(函数指针) 强制多态(Coercion Polymorphism,编译期/运行期):基本类型转换、自定义类型转换 2. 虚表指针、虚函数指针、虚函数表 虚表指针:在含有虚函数的类的对象中,指向虚函数表的指针,在运行时确定 虚函数指针:指向虚函数的地址的指针 {vfptr} 虚函数表:在程序只读数据段,存放虚函数指针,如果派生类实现了基类的某个虚函数,则在虚函数表中覆盖原本基类的那个虚函数指针,在编译时根据类的声明创建 Shape::$vftable@ class Shape { public: virtual ~Shape(){ cout << "~Shape()" << endl; } }; class Point { public: ~Point(){ cout << "~Point()" << endl; } private: int m_x{0}; int m_y{0}; char m_c; }; class Circle : public Shape { public: ~Circle(){ cout << "~Circle()" << endl; } private: Point m_p; }; int main( ) { // 8 类中存有指向虚函数表的指针 cout << sizeof(Shape) << endl; // 16 类中存有指向虚函数表的指针 // 以及Point对象的大小(此时Point类中不包含任何变量),虽然真实大小是 8 + 1 // 但是额外多的1个字节导致内存大小扩增了 8(每次扩增的最小数值是8 <alignment member> (size=7)) cout << sizeof(Circle) << endl; // 8 类中的int占4个字节,char占1个字节 // 但每次扩增的最小数值是4(<alignment member> (size=3)) cout << sizeof(Point) << endl; Circle c; return 0; } Start 8 24 12 ~Circle() ~Point() ~Shape() 0 Finish Shape 类...