当前位置: 首页 > news >正文

网页设计与网站建设的概述网易邮箱163登录入口

网页设计与网站建设的概述,网易邮箱163登录入口,国内产品设计网站,如何使用wordpress搭建网站《C新经典设计模式》之附录A 类和对象 A.1 静态对象的探讨与全局对象的构造顺序A.1.1 静态对象的探讨A.1.1.cpp A.1.2 全局对象的构造顺序问题A.1.2.cpp A.2 拷贝构造函数和拷贝赋值运算符A.2.1 拷贝构造函数和拷贝赋值运算符的书写A.2.1.cpp A.2.2 对象自我赋值产生的问题A.2.… 《C新经典设计模式》之附录A 类和对象 A.1 静态对象的探讨与全局对象的构造顺序A.1.1 静态对象的探讨A.1.1.cpp A.1.2 全局对象的构造顺序问题A.1.2.cpp A.2 拷贝构造函数和拷贝赋值运算符A.2.1 拷贝构造函数和拷贝赋值运算符的书写A.2.1.cpp A.2.2 对象自我赋值产生的问题A.2.2.cpp A.2.3 继承关系下拷贝构造函数和拷贝赋值运算符的书写A.2.3.cpp A.2.4 拷贝构造函数和拷贝赋值运算符中的重复代码 A.3 类的public继承is-a关系及代码编写规则A.3.1 子类遮蔽父类的普通成员函数A.3.1.cpp A.3.2 父类的纯虚函数接口A.3.2.cpp A.3.3 父类的虚函数接口A.3.3.cpp A.3.4 为纯虚函数指定实现体A.3.4.cpp A.3.5 类的public继承is-a关系综合范例A.3.5.cpp A.3.6 public继承关系下的代码编写规则A.3.cpp A.4 类与类之间的组合关系与委托关系A.4.1 组合关系A.4.1.cpp A.4.2 委托关系A.4.2.cpp A.5 类的private继承探讨A.5.cpp A.6 不能被拷贝构造和拷贝赋值的类对象A.6.cpp A.7 虚析构函数的内存泄露问题A.7.cpp A.8 类设计技巧A.8.1 提供成员变量的访问接口A.8.1.cpp A.8.2 避免父类虚函数暴露给子类A.8.2.cpp A.8.3 构造与析构函数中避免调用虚函数A.8.3.cpp A.8.4 虚函数的虚与非虚A.8.4.cpp A.8.5 抽象类的模拟A.8.5.cpp A.8.6 避免隐式类型转换A.8.6.cpp A.8.7 强制类对象在堆或栈上分配A.8.7.1.cppA.8.7.2.cpp A.9 命名空间注意事项A.9.cpp A.10 类定义的依赖与前向声明A.10.cpp A.1 静态对象的探讨与全局对象的构造顺序 A.1.1 静态对象的探讨 类中类类型的静态成员变量即使未被使用也会被构造和析构。 inline static 类类型的成员变量会同时声明和定义 A.1.1.cpp #include iostream using namespace std;namespace ns1 {class A{int m_i;public:A() { cout ns1::A::A()\n; }~A() { cout ns1::A::~A()\n; }};class B{public:static A m_sa; // 类B中静态成员变量类类型Am_sa未使用可以只声明不定义}; }namespace ns2 {class A{public:int m_i;A() { cout ns2::A::A()\n; }~A() { cout ns2::A::~A()\n; }};class B{public:static A m_sa; // 声明};// 类B中静态成员变量类类型Am_sa使用必须定义// m_sa定义时未使用也会构造和析构A B::m_sa; }namespace ns3 {class A{public:A() { cout ns3::A::A()\n; }~A() { cout ns3::A::~A()\n; }};class B{public:inline static A m_sa; // inline静态成员变量同时声明和定义m_sa即使未使用也会构造和析构// inline static int a;//简单类型未使用时可能不会分配内存}; }namespace ns4 {class A{public:A() { cout ns4::A::A()\n; }~A() { cout ns4::A::~A()\n; }};// 函数中类类型的静态对象函数未调用则不会被构造// 函数调用多次只会被构造一次void myfunc(){static A aboj;} }int main() { #if 0 ns1::B bobj; #endif#if 0 ns2::B bobj;cout bobj.m_sa.m_i endl; #endif#if 0 ns3::B bobj; #endif#if 1using namespace ns4;myfunc();myfunc(); #endifcout Over!\n;return 0; }A.1.2 全局对象的构造顺序问题 函数中静态对象在函数第一次执行到时仅初始化一次。 全局对象的的初始化顺序无法保证C只保证特定编译单元*.cpp中全局对象的的初始化顺序。 A.1.2.cpp #include iostream using namespace std;class A2 { public:int m_i;A2() : m_i(5) { cout A2::A2()\n; }~A2() { cout A2::~A2()\n; } };A2 getA2Obj() {static A2 a2;return a2; }class A1 { public:A1(){cout getA2Obj().m_i endl;cout A1::A1()\n;}~A1(){cout A1::~A1()\n;} };int main() {{A1 a1;}cout Over!\n;return 0; }A.2 拷贝构造函数和拷贝赋值运算符 A.2.1 拷贝构造函数和拷贝赋值运算符的书写 A.2.1.cpp #include iostream using namespace std;class A { public:int m_caa;int m_cab;A() : m_caa(0), m_cab(0) { cout A::A()\n; }~A() { cout A::~A()\n; }A(const A tmpobj) // 拷贝构造函数{cout A::A(const A)\n;m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;}A operator(const A tmpobj) // 拷贝赋值运算符{cout A A::operator(const A)\n;m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;return *this;} };void test(const A a) { cout test(const A a)\n; }int main() {{A aobj1;aobj1.m_caa 10;aobj1.m_cab 20;A aobj2 aobj1; // 调用拷贝构造函数aobj2 aobj1; // 调用拷贝赋值运算符}cout Over!\n;return 0; }A.2.2 对象自我赋值产生的问题 A.2.2.cpp #include iostream #include cstring using namespace std;namespace ns1 {class A{public:int m_caa;int m_cab;char *m_cap;A() : m_caa(0), m_cab(0), m_cap(new char[100]) { cout A::A()\n; }~A(){cout A::~A()\n;delete[] m_cap;}A(const A tmpobj) // 拷贝构造函数{cout A::A(const A)\n;common(tmpobj);}A operator(const A tmpobj) // 拷贝赋值运算符{cout A A::operator(const A)\n;if (this ! tmpobj){delete m_cap;common(tmpobj);}return *this;}private:void common(const A tmpobj){m_cap new char[100];memcpy(m_cap, tmpobj.m_cap, 100);m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;}}; }namespace ns2 {class A{public:int m_caa;int m_cab;char *m_cap;A() : m_caa(0), m_cab(0), m_cap(new char[100]) { cout A::A()\n; }~A(){cout A::~A()\n;delete[] m_cap;}A(const A tmpobj) // 拷贝构造函数{cout A::A(const A)\n;m_cap new char[100];memcpy(m_cap, tmpobj.m_cap, 100);m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;}A operator(const A tmpobj) // 拷贝赋值运算符{cout A A::operator(const A)\n;char *ptmp new char[100];memcpy(ptmp, tmpobj.m_cap, 100);delete m_cap;m_cap ptmp;m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;return *this;}}; }int main() { #if 0{ns1::A aobj2;strcpy(aobj2.m_cap, abcdefg);aobj2 aobj2; // 调用拷贝赋值运算符} #endif#if 1{ns2::A aobj2;strcpy(aobj2.m_cap, abcdefg);aobj2 aobj2; // 调用拷贝赋值运算符} #endifcout Over!\n;return 0; }A.2.3 继承关系下拷贝构造函数和拷贝赋值运算符的书写 如果子类中写了拷贝构造函数或者拷贝赋值运算符 那么父类中的拷贝构造函数和拷贝赋值运算需要自己调用 编译器不会自动调用父类中对应的拷贝构造函数和拷贝赋值运算符 A.2.3.cpp #include iostream #include cstring using namespace std;namespace ns1 {class A{public:int m_caa;int m_cab;char *m_cap; // 指向定长100个字节的内存A() : m_caa(0), m_cab(0), m_cap(new char[100]) { cout A::A()\n; }virtual ~A(){cout A::~A()\n;delete[] m_cap;}A(const A tmpobj) // 拷贝构造函数{cout A::A(const A)\n;m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;m_cap new char[100];memcpy(m_cap, tmpobj.m_cap, 100);}A operator(const A tmpobj) // 拷贝赋值运算符{cout A::A operator(const A)\n;if (this ! tmpobj){m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;memcpy(m_cap, tmpobj.m_cap, 100);}return *this;}};class B : public A{}; }namespace ns2 {class A{public:int m_caa;int m_cab;char *m_cap; // 指向定长100个字节的内存A() : m_caa(0), m_cab(0), m_cap(new char[100]) { cout A::A()\n; }virtual ~A(){cout A::~A()\n;delete[] m_cap;}A(const A tmpobj) // 拷贝构造函数{cout A::A(const A)\n;m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;m_cap new char[100];memcpy(m_cap, tmpobj.m_cap, 100);}A operator(const A tmpobj) // 拷贝赋值运算符{cout A::A operator(const A)\n;if (this ! tmpobj){m_caa tmpobj.m_caa;m_cab tmpobj.m_cab;memcpy(m_cap, tmpobj.m_cap, 100);}return *this;}};class B : public A{public:B() { cout B::B()\n; }~B() { cout B::~B()\n; }B(const B tmpobj) : A(tmpobj) // 拷贝构造函数调用了类A的拷贝构造函数{cout B::B(const B)\n;// A(tmpobj); //意图调用类A的拷贝构造函数存在二义性函数调用或者对象定义A tmpobj。}B operator(const B tmpobj) // 拷贝赋值运算符{if (this ! tmpobj){A::operator(tmpobj); // 调用类A的拷贝赋值运算符cout B::B operator(const B)\n;}return *this;}}; }int main() { #if 0{using namespace ns1;B bobj1;bobj1.m_caa 100;bobj1.m_cab 200;strcpy(bobj1.m_cap, new class);B bobj2 bobj1; // 执行类A的拷贝构造函数bobj2 bobj1; // 执行类A的拷贝赋值运算符} #endif#if 1{using namespace ns2;B bobj1;bobj1.m_caa 100;bobj1.m_cab 200;strcpy(bobj1.m_cap, new class);B bobj2 bobj1; // 执行拷贝构造函数bobj2 bobj1; // 执行拷贝赋值运算符bobj2 bobj2;} #endifcout Over!\n;return 0; }A.2.4 拷贝构造函数和拷贝赋值运算符中的重复代码 重复代码写成private函数去调用。 A.3 类的public继承is-a关系及代码编写规则 public继承关系的检验规则能够在父类对象上做的行为也必然能在子类对象上做每个子类对象同时也都是一个父类对象。 里氏替换Liskov替换原则任何父类出现的地方都应该可以无差别的使用子类替换。 A.3.1 子类遮蔽父类的普通成员函数 public继承中不建议子类遮蔽父类的普通成员函数这样子类就会有不同的行为。 A.3.1.cpp #include iostream using namespace std;class Human { public:virtual ~Human() {}void eat() { cout human eat food endl; } };class Man : public Human // 公有继承 { public:void eat(){cout man eat food endl;} };int main() {Man myman;myman.eat();myman.Human::eat();cout Over!\n;return 0; }A.3.2 父类的纯虚函数接口 纯虚函数的父类变成抽象类不能生成该类对象。 从抽象类继承的子类必须实现该接口。 A.3.2.cpp #include iostream using namespace std;class Human { public:virtual ~Human() {}virtual void work() 0; // 纯虚函数抽象基类 };class Man : public Human // 公有继承 { public:virtual void work() override { cout heavy work endl; } };class Woman : public Human { public:virtual void work() override { cout light work endl; } };int main() {Man myman;myman.work();Woman mywoman;mywoman.work();cout Over!\n;return 0; }A.3.3 父类的虚函数接口 父类的虚函数接口让子类继承成员函数接口和实现同时子类可以提供自己新的实现。 A.3.3.cpp #include iostream using namespace std;class Human { public:virtual ~Human() {}virtual void avlf() { cout about 75 endl; } // 普通虚函数 };class Man : public Human // 公有继承 { public:virtual void avlf() override { cout about 72 endl; } };class Woman : public Human { public:virtual void avlf() { cout about 80 endl; } };int main() {Man myman;myman.avlf();Woman mywoman;mywoman.avlf();cout Over!\n;return 0; }A.3.4 为纯虚函数指定实现体 纯虚函数强制子类去实现。 父类中纯虚函数增加实现体方便子类直接调用。 A.3.4.cpp #include iostream using namespace std;class Human { public:virtual ~Human() {}virtual void avlf() 0; // 纯虚函数强制子类实现 }; // 增加实现体可用于子类调用 void Human::avlf() { cout about 75 endl; }class Man : public Human // 公有继承 { public:virtual void avlf() override { cout about 72 endl; } };class Woman : public Human { public:virtual void avlf() { Human::avlf(); } };int main() {Man myman;myman.avlf();Woman mywoman;mywoman.avlf();cout Over!\n;return 0; }A.3.5 类的public继承is-a关系综合范例 A.3.5.cpp #include iostream using namespace std;class A { }; class B : public A { }; class C : public B { }; void myfunc(A tmpa) {cout myfunc(A tmpa) endl; } /* void myfunc(B tmpb) {cout myfunc(B tmpb) endl; } */ void myfunc(C tmpc) {cout myfunc(C tmpc) endl; }int main() {A myobja;myfunc(myobja);B myobjb;myfunc(myobjb);C myobjc;myfunc(myobjc);cout Over!\n;return 0; }A.3.6 public继承关系下的代码编写规则 父类的普通成员函数子类不应该覆盖。父类的纯虚函数只定义接口具体实现子类完成。父类的普通虚函数定义接口并编写实现子类可编写实现。能非public继承时就不要使用public继承。 A.3.cpp #include iostream using namespace std;namespace ns1 {class Human{public:Human() { cout Human::Human() endl; }virtual ~Human() { cout Human::~Human() endl; }void eat() { cout human eat food endl; }virtual void avlf() { cout about 75 endl; } // 普通虚函数virtual void work() 0; // 纯虚函数抽象基类};class Man : public Human // 公有继承{public:Man() { cout Man::Man() endl; }~Man() { cout Man::~Man() endl; }void eat(){Human::eat(); // 调用父类的同名函数cout man eat food endl;}virtual void work() override { cout heavy work endl; }virtual void avlf() override { cout about 72 endl; }};class Woman : public Human{public:Woman() { cout Woman::Woman() endl; }~Woman() { cout Woman::~Woman() endl; }virtual void work() override { cout light work endl; }virtual void avlf() override{Human::avlf(); // 调用父类的同名函数cout about 80 endl;}}; }namespace ns2 {class Human{public:virtual ~Human() {}void eat() { cout human eat food endl; }virtual void avlf() 0; // 纯虚函数强制子类实现virtual void work() 0; // 纯虚函数};void Human::avlf() // 实现可用于子类调用{cout about 75 endl;}class Man : public Human // 公有继承{public:virtual void avlf() override{Human::avlf(); // 调用父类的同名函数cout about 72 endl;}virtual void work() override { cout heavy work endl; }};class Woman : public Human{public:virtual void avlf() override{Human::avlf(); // 调用父类的同名函数cout about 80 endl;}virtual void work() override { cout light work endl; }}; }namespace ns3 {class A{};class B : public A{};class C : public B{};void myfunc(A tmpa){cout myfunc(A tmpa) endl;}/*void myfunc(B tmpb){cout myfunc(B tmpb) endl;}*/void myfunc(C tmpc){cout myfunc(C tmpc) endl;} }int main() { #if 0{ns1::Man myman;myman.eat();myman.Human::eat();} #endif#if 0{ns2::Woman mywoman;mywoman.avlf();} #endif#if 1{using namespace ns3;A myobja;myfunc(myobja);B myobjb;myfunc(myobjb);C myobjc;myfunc(myobjc);} #endifcout Over!\n;return 0; }A.4 类与类之间的组合关系与委托关系 A.4.1 组合关系 一个类的定义中含有其它类类型成员变量。 A.4.1.cpp #include iostream #include map #include string #include memory using namespace std;namespace ns1 {class Info{string m_name; // 名字int m_gender; // 性别int m_age; // 年龄};class Human{public:Info m_info;}; }namespace ns2 {template typename T, typename Uclass smap{multimapT, U container;public:void insert(const T key, const U value){auto iter container.find(key);if (iter container.end())container.insert(make_pair(key, value));elseiter-second value;}U getValue(const T key) const{auto iter container.find(key);return iter-second;}size_t size() const { return container.size(); }}; }int main() { #if 0ns1::Human myhuman;#endif#if 1{multimapint, int tmpmpc;tmpmpc.insert(make_pair(1, 1));tmpmpc.insert(make_pair(2, 3));tmpmpc.insert(make_pair(1, 2));cout tmpmpc.size() tmpmpc.size() endl;cout tmpmpc.count(1) endl;for (auto e : tmpmpc)cout e.first --- e.second endl;cout endl;ns2::smapint, int tmpsmap;tmpsmap.insert(1, 1);tmpsmap.insert(2, 3);tmpsmap.insert(1, 2);cout tmpsmap.size() tmpsmap.size() endl;cout tmpsmap.getValue(1) endl;} #endifcout Over!\n;return 0; }A.4.2 委托关系 一个类中包含指向另一个类的指针。 A.4.2.cpp #include iostream #include map #include string #include memory using namespace std;namespace ns1 {class A{public:void funca() {}};class B{A *m_pa;public:B(A *tmpa nullptr) : m_pa(tmpa) {}void funcb(){if (m_pa ! nullptr)m_pa-funca();}}; }namespace ns2 {class A{public:void funca() {}};class B{shared_ptrA m_pa;public:B(const shared_ptrA tmpa nullptr) : m_pa(tmpa) {}void funcb(){if (m_pa ! nullptr)m_pa-funca();}}; }int main() {#if 0{using namespace ns1;A *pa new A();B *pb new B(pa);pb-funcb();delete pb;delete pa;} #endif#if 1{using namespace ns2;shared_ptrA pa(new A());shared_ptrB pb(new B(pa));pb-funcb();} #endifcout Over!\n;return 0; }A.5 类的private继承探讨 private继承是一种组合关系确切的说是组合关系中的 is-implemented-in-terms-of关系根据…实现出。一般优先考虑使用组合关系只有在一些比较特殊的情况和必要的情况下比如牵扯一些protected成员、private成员、虚函数等才考虑到用private来表达组合关系。 A.5.cpp #include iostream #include map using namespace std;namespace ns1 {class Human{public:virtual ~Human() { cout ~Human() endl; }Human() { cout Human() endl; }};class Man : public Human{public:~Man() { cout ~Man() endl; }Man() { cout Man() endl; }};class A{public:~A() { cout ~A() endl; }A() { cout A() endl; }A(const A ) { cout A(const A)\n; }A operator(const A tmpobj){if (this ! tmpobj)cout A operator(const A)\n;return *this;}};class B : public A{public:~B() { cout ~B() endl; }B() { cout B() endl; }B(const B tmpobj) : A(tmpobj) { cout B(const B)\n; }B operator(const B tmpobj){if (this ! tmpobj){A::operator(tmpobj);cout B operator(const B)\n;}return *this;}};void f(A aobj) { cout f(A aobj) endl; } }namespace ns2 {class Human{public:virtual ~Human() {}};class Man : private Human{};class A{};class B : private A{};void f(A aobj) {} }namespace ns3 {消息队列类class MsgQueue{//...入消息队列出消息队列};class Timer{public:Timer(int inttimems); // inttimems间隔多少毫秒调用一次CallBackvirtual void CallBack(); // 一个到时间后会被调用的虚函数//....定时器的编写有一定复杂度这里不详细探讨};消息队列类class MsgQueue2 : private Timer{//...入消息队列出消息队列// 构造函数等....private:virtual void CallBack(); // 一个到时间后会被调用的虚函数}; }int main() { #if 0{using namespace ns1;Man myman;Human myhuman myman; // 父类引用绑定子类对象Human *myhuman2 new Man(); // 父类指针指向子类对象delete myhuman2;B bobj;f(bobj);A aobj; //aobj bobj;} #endif#if 1{using namespace ns2;Man myman;//Human myhuman myman; // error// Human *myhuman2 new Man(); // errorB bobj;// f(bobj); // error// A aobj bobj; // error} #endifcout Over!\n;return 0; }A.6 不能被拷贝构造和拷贝赋值的类对象 不能被拷贝构造的类对象具有实际意义。 CWindLock类构造函数进入临界区析构函数离开临界区加锁解锁显然不应该允许被复制。 A.6.cpp #include iostream #include map using namespace std;namespace ns1 {class A{}; }namespace ns2 {class A{public:A() {} // 因为编写了拷贝构造或者拷贝赋值禁止必须提供一个构造函数A(const A ) delete;//禁止拷贝构造A operator(const A ) delete;//禁止拷贝赋值运算符}; }namespace ns3 {class A{private: // 成员函数或者友元函数能够访问这两个函数A(const A ) {}A operator(const A ) { return *this; }public:A() {} // 必须提供构造函数void func(const A aobj) // 成员函数或者友元函数能够执行拷贝构造函数和拷贝赋值运算符{*this aobj; // 拷贝赋值A aobj2(aobj); // 拷贝构造}}; }namespace ns4 {class A{private://只保留函数声明编译链接时会报告链接错误A(const A );A operator(const A );public:A() {} // 必须提供构造函数void func(const A aobj) // 成员函数或者友元函数能够执行拷贝构造函数和拷贝赋值运算符{*this aobj; // 拷贝赋值A aobj2(aobj); // 拷贝构造}}; }namespace ns5 {class noncopyable{private://只声明未实现子类拷贝构造和赋值时无法调用。noncopyable(const noncopyable );noncopyable operator(const noncopyable );protected: // 只允许本类和子类成员访问noncopyable(){};~noncopyable(){};};// noncopyable不能被拷贝子类也不行//A对象具备noncopyable对象的不允许拷贝的特性组合关系private继续非public继承class A : private noncopyable // 根据...实现出组合关系通过noncopyable类实现出A类{public:void func(const A aobj){//*this aobj; //禁止调用拷贝赋值运算符// A aobj2(aobj); //禁止调用拷贝构造函数}}; }int main() { #if 0{using namespace ns1;A aobj1; // 构造A aobj2(aobj1); // 拷贝构造A aobj3 aobj2; // 拷贝构造A aobj4;aobj4 aobj3; // 拷贝赋值} #endif#if 0{using namespace ns2;A aobj1;// A aobj2(aobj1); //禁止拷贝构造A aobj3;// aobj3 aobj1; //禁止拷贝赋值} #endif#if 0{using namespace ns3;A aobj1;A aobj3;aobj3.func(aobj1);} #endif#if 0{using namespace ns4;A aobj1;A aobj3;// aobj3.func(aobj1);//未实现拷贝构造和拷贝赋值编译连接时报错} #endif#if 1{using namespace ns5;A aobj1;// A aobj2(aobj1); //禁止拷贝构造A aobj3;// aobj3 aobj1; //禁止拷贝赋值} #endifcout Over!\n;return 0; }A.7 虚析构函数的内存泄露问题 父类指针指向子类时若父类析构函数非虚则子类的析构函数不执行父类虚析构函数中会自动调用子类的析构函数。 虚函数虚函数表多出4或8字节。(不做父类不应该有虚函数) 不要随便public继承一个自己不熟悉的类(若父类无virtual析构函数delete子类时子类析构函数可能不会被调用) C11 final不希望该类被继承 只有父类指针指向子类对象父类引用绑定子类对象这种多态形式的代码存在的时候父类才有必要写一个虚析构函数public修饰。 a)如果子类public继承父类那么父类指针可以指向子类对象b)如果子类private或者protected继承父类那么父类指针不可以指向子类对象c)如果让父类指针指向子类对象那么就需要用public继承这个时候父类就需要提供虚析构函数。 总结类中存在虚析构函数的情形 a)一般如果父类中有其它虚函数意味着会按照多态的方式来使用该父类也就是一般会存在父类指针指向子类对象的情形 那么此时父类中应该有一个public修饰的虚析构函数。b)如果代码中并不会出现父类指针指向子类对象父类引用绑定子类对象的多态情形那么父类中不需要有虚析构函数。同时在文档中应该明确告知开发者不应该public继承该类而应该尽量用private。c)如果某个类并不作为父类使用那么不应该在该类中存在虚析构函数。 A.7.cpp #include iostream #include memory using namespace std;namespace ns1 {class noncopyable{private:noncopyable(const noncopyable );noncopyable operator(const noncopyable );protected: // 只允许本类和子类成员访问noncopyable(){};~noncopyable(){};};class A : public noncopyable{};class ThirdPartClass{public:ThirdPartClass(){cout ThirdPartClass:ThirdPartClass()\n;}~ThirdPartClass(){cout ThirdPartClass:~ThirdPartClass()\n;}};class B : public ThirdPartClass{public:char *m_p;B(){cout B:B()\n;m_p new char[100];}~B(){cout B:~B()\n;delete m_p;}}; }namespace ns2 {class noncopyable{private:noncopyable(const noncopyable );noncopyable operator(const noncopyable );protected: // 只允许本类和子类成员访问noncopyable(){};~noncopyable(){};};class A : private noncopyable{public:A() { cout A:A()\n; }~A() { cout A:~A()\n; }};class ThirdPartClass{public:ThirdPartClass(){cout ThirdPartClass:ThirdPartClass()\n;}virtual ~ThirdPartClass(){cout ThirdPartClass:~ThirdPartClass()\n;}};class B : public ThirdPartClass{public:char *m_p;B(){cout B:B()\n;m_p new char[100];}~B(){cout B:~B()\n;delete m_p;}}; }int main() { #if 0{using namespace ns1;ThirdPartClass *ptp new B(); // 父类指针指向子类对象delete ptp; // 父类无虚析构函数子类析构函数不会被调用内存泄漏} #endif#if 0{using namespace ns1;// 如果子类private或者protected继承父类那么父类指针不可以指向子类对象noncopyable *pnca new A();// delete pnca;//errorpnca的析构函数是protected类型的无法外部被调用} #endif#if 0{using namespace ns2;A *pa new A();delete pa;shared_ptrA pb(new A());} #endif#if 1{using namespace ns2;ThirdPartClass *pa new B();delete pa;cout endl;B *pb new B();delete pb;cout endl;shared_ptrThirdPartClass pc(new B());shared_ptrB pd(new B());} #endifcout Over!\n;return 0; }A.8 类设计技巧 A.8.1 提供成员变量的访问接口 当需要队成员变量进行访问时可以使用private来修饰成员变量然后提供一个public修饰的成员函数作为外界访问该成员变量的接口。 A.8.1.cpp #include iostream using namespace std;namespace ns1 {class A1{public:int m_a;};class A2{int m_a;public:int getA() { return m_a; }}; }int main() { #if 0{using namespace ns1;A1 a1obj;a1obj.m_a 3;cout a1obj.m_a endl;A2 a2obj;a2obj.getA() 5;cout a2obj.getA() endl;} #endifcout Over!\n;return 0; }A.8.2 避免父类虚函数暴露给子类 如果能将虚函数设置为私有则优先考虑将其设置为私有。 A.8.2.cpp #include iostream using namespace std;namespace ns1 {class A{private:// public:virtual void myvirfunc() { cout A::myvirfunc() endl; }public:virtual ~A() {}void myfunc() { myvirfunc(); }};class B : public A{private:virtual void myvirfunc() override { cout B::myvirfunc() endl; }}; }int main() { #if 1{using namespace ns1;A *pobj new B();pobj-myfunc();// pobj-A::myvirfunc();delete pobj;} #endifcout Over!\n;return 0; }A.8.3 构造与析构函数中避免调用虚函数 设想有父子关系的两个类 a)如果在父类的构造函数中调用了一个子类的虚函数是无法做到的因为执行到父类的构造函数体时对象的子类部分还没被构造出来未成熟的对象。b)如果在父类的析构函数中调用了一个子类的虚函数是无法做到的因为执行到父类的析构函数体时对象的子类部分其实已经销毁了。 不要在类的构造函数和析构函数中调用虚函数在构造函数和析构函数中虚函数可能会失去虚函数的作用而被当做普通函数看到。 A.8.3.cpp #include iostream using namespace std;class ANew { public:ANew() { f1(); }virtual ~ANew() { f2(); }// 定义两个虚函数virtual void f1() { cout virtual ANew::f1() endl; }virtual void f2() { cout virtual ANew::f2() endl; }// 定义普通成员函数调用虚函数void AClassFunc() { f1(); } };class BNew : public ANew { public:BNew() { f1(); }virtual ~BNew() { f2(); }// 定义两个虚函数virtual void f1() override { cout virtual BNew::f1() endl; }virtual void f2() override { cout virtual BNew::f2() endl; } };int main() {ANew *pnew new BNew();cout -----------begin----------- endl;pnew-f1();pnew-f2();pnew-AClassFunc();cout -----------end----------- endl;delete pnew;cout Over!\n;return 0; }A.8.4 虚函数的虚与非虚 父类析构函数不一定非是虚函数。但是当父类指针指向子类对象父类引用绑定子类对象这种多态形式的代码存在时父类是需要写一个public修饰的虚析构函数的这样就可以通过父类的接口来多态的销毁子类对象否则就可能会造成内存泄漏。 noncopyable其析构函数是用protected修饰的而且noncopyable的析构函数并不是虚函数仅仅用protected修饰一下析构函数就达到了几个效果 a)无法创建父类对象 b)无法让父类指针指向父类或者子类对象因为无法成功delete a)如果一个父类的析构函数不是虚函数并且也不利用这个父类创建对象也不会用到这个父类类型的指针则应该考虑将该父类的析构函数使用protected而非public来修饰以防止写出错误的代码增加代码编写安全性防止误用。 b)其实父类的析构函数不是虚函数本身就暗示着不会通过父类的接口来多态的销毁子类对象也暗示着不会用到父类类型的指针。 A.8.4.cpp #include iostream using namespace std;class ANew2 { protected:~ANew2() {} }; class BNew2 : public ANew2 { };int main() {// ANew2 aobj;//error析构函数非publicANew2 *paobj new ANew2();// delete paobj;//error无法deleteANew2指针ANew2 *paobj2 new BNew2();// delete paobj2;//error无法deleteANew2指针// 子类能够调用protected的父类析构函数BNew2 bobj;BNew2 *pbobj new BNew2();delete pbobj;cout Over!\n;return 0; }A.8.5 抽象类的模拟 抽象类要求至少有一个纯虚函数接口规范不能用来生成对象统一管理子类。 将模拟的抽象类的构造函数和拷贝构造函数都使用protected来修饰。将模拟的抽象类的析构函数设置为纯虚函数并在类定义之外为该纯虚函数定义函数体。将模拟的抽象类的析构函数使用protected来修饰。 A.8.5.cpp #include iostream using namespace std;namespace ns1 {class PVC{protected:PVC(){}; // 构造函数PVC(const PVC ){}; // 拷贝构造函数};class SubPVC : public PVC{}; }namespace ns2 {class PVC{public:virtual ~PVC() 0;};// 类外实现类析构函数(绝大部分纯虚函数没有实现体但纯虚析构函数是个特例为了释放资源等所以一般要有实现体。// 子类析构函数会隐式地调用父类的析构函数PVC::~PVC() {}class SubPVC : public PVC{public:~SubPVC() // 编译器会插入调用父类析构函数的代码{}}; }namespace ns3 {class PVC{protected:~PVC(){};};class SubPVC : public PVC{}; }int main() { #if 0{using namespace ns1;SubPVC mysubobj1;SubPVC mysubobj2(mysubobj1); // 子类能够调用protected的父类构造函数// protected构造函数的类无法创建// PVC myobj1;// PVC myobj2(myobj1);} #endif#if 0{using namespace ns2;SubPVC mysubobj; // 析构时编译器会先执行该类自己的析构函数体再执行父类的析构函数体PVC *p new SubPVC();delete p;} #endif#if 1{using namespace ns3;SubPVC mysubobj1;SubPVC mysubobj2(mysubobj1);SubPVC *pobj new SubPVC();delete pobj;// protected析构函数无法创建类// PVC myobj1;// PVC myobj2(myobj1);PVC *p1 new PVC();// delete p1;//protected析构函数无法deletePVC *p2 new SubPVC();// delete p2;//protected析构函数无法delete} #endifcout Over!\n;return 0; }A.8.6 避免隐式类型转换 A.8.6.cpp #include iostream using namespace std;class A { public: // explicit避免隐射类型转换explicit A(int i) // 类型转换构造函数一个形参为待转换的数据类型非本类的const引用{cout i endl;} };int main() {// 编译器通过构造函数把数字15转换成一个A类型的类对象临时对象并构造在aobj对象预留的空间里。// A aobj 15; //explicit禁止隐形类型转换A aobj A(15);A aobj2(20);cout Over!\n;return 0; }A.8.7 强制类对象在堆或栈上分配 类对象不可以在堆上分配内存 重载类中的operator new和operator delete操作符。 A.8.7.1.cpp #include iostream using namespace std;class A { private:static void *operator new(size_t size);static void operator delete(void *phead);static void *operator new[](size_t size);static void operator delete[](void *phead); };int main() {A paobj;A paobjarray[3];// 禁止堆上分配// A *paobj new A();// delete paobj;// A *paobjarray new A[3]();// delete[] paobjarray;cout Over!\n;return 0; }强制类对象只可以在堆上分配内存 A.8.7.2.cpp #include iostream using namespace std;class A { private:~A() {}public:void destroy(){delete this;} };int main() {// A aobj;//禁止栈上分配A *paobj new A();// delete paobj;paobj-destroy(); // 释放内存cout Over!\n;return 0; }A.9 命名空间注意事项 using声明的命名空间代码行不要放在.h头文件中。.cpp文件中using声明的命名空间代码行放在所有#include语句行后面。 A.9.cpp #include iostream using namespace std; // 声明std命名空间namespace a1nsp {class A{}; } using namespace a1nsp; // 声明a1nsp命名空间namespace a2nsp {class A{}; } using namespace a2nsp; // 声明a2nsp命名空间int main() {// A aobj; //名字冲突a1nsp::A aobj;cout Over!\n;return 0; }A.10 类定义的依赖与前向声明 类前向声明解决类相互依赖的问题。 类A1和类A2直接依赖。一般避免这种设计而是 引入一个新类让A1和A2类都依赖于这个新类从而打破这种类A1和A2的依赖关系。 类的前向声明并不是类的完整定义 有些情况下必须要类的完整定义而不是类的前向声明 a)在类A1的定义中加入A2类型的对象。b)在类A1的定义中需要知道A2类型对象的大小。c)在类A1的定义中需要调用类A2的成员函数时。 A.10.cpp #include iostream using namespace std;class A1; // 类A1的前向声明 class A2 { public:A1 *m_pa1;void a2func() {} };class A1 { public:A2 *m_pa2;void a1func_1(){int tmpvalue sizeof(A2); // 使用了未定义类型“A2”}void a1func_2(){m_pa2-a2func(); // 使用了未定义类型“A2”} };int main() {cout Over!\n;return 0; }
http://wiki.neutronadmin.com/news/251829/

相关文章:

  • 戈韦思网站建设付网站建设费
  • 网站建设销售一个月营业额网站开发常用的语言
  • 导航网站怎么做的南京最新情况最新消息今天
  • 网站建设公司宣传册宁波建设局网站首页
  • 谷歌云 wordpress 建站凯里做网站的公司
  • 海南省交通建设局网站网站建设与管理复习知识点
  • 朝阳区手机网站设计服务o2o商城系统
  • 闽侯做网站凡科互动官网登陆
  • 在合肥做网站前端月薪大概多少先进的网站建设
  • 秦皇岛做网站公司排名山西网络建站代运营
  • 室内设计方案网站泌阳网站建设
  • 做网站需要编程基础商务网站建设心得
  • 优酷视频放到网站上怎么做公司年审需要多少钱
  • 手机网站开发框架网站兼容手机
  • 南宁 建网站江门有什么网站推广
  • 金水区做网站酷站是什么网站
  • 桂林dj网站网站上面的主导航条怎么做
  • 做网站的收益来源佛山网站关键词优化公司
  • 网站建设worldpress手机网站开发的目的
  • 承德的网站建设公司免费推广的方式
  • 瑞丽市建设局网站贵阳白云区城乡建设局网站
  • 医院响应式网站建设方案网站做全好吗
  • 大气好看的网站陕西网站建设公司排名
  • 做网站的空间是啥广州市网页设计制作
  • 企业网站创建步wordpress不停刷y
  • 网站定制哪个好用阿里云怎么建网站
  • 个人网站建设方案书怎么写网站功能模块什么意思
  • 做公众号的网站模板下载吗济南网站建设内容设计
  • 怀远县建设局网站网页界面设计
  • 淄博公司做网站做百科权威网站有哪些