本文共 4747 字,大约阅读时间需要 15 分钟。
为什么C语言没有面向对象的思维方式?
C语言主要与硬件打交道,因此其不需要那么多的抽象思维。
为什么默认的析构函数不是虚函数呢?
为了效率,因为虚析构函数需要插入很多代码。而一些类没有必要产生继承关系,因此默认的析构函数是非虚函数。
OO.h
#ifndef FND_CPP_OO_H#define FND_CPP_OO_H//#include#include
logic.cpp
#include "OO.h"#include "Event.h"int main() { Drived *info = new Drived(1); Grouped *group = new Grouped(2); Event ev; group->print(); group->act(ev); group->addBase(info); group->removeBase(info->id()); group->id(); Base* baseGroup = group; baseGroup->act(ev); baseGroup->print(); baseGroup->id(); //下面这两个调用不到,因为这两个是派生类的成员函数 //baseGroup->addBase(info); //baseGroup->removeBase(info->id()); //如果希望将基类指针转换成派生类指针,有以下三种方式 Grouped *g = static_cast(baseGroup); //不安全 Grouped *g2 =dynamic_cast (baseGroup); //安全,转换失败的返回值是零 Grouped *g3 = (Grouped*)(baseGroup); //如果代码中出现static_cast或dynamic_cast,会不会是因为基类接口太少了。 //但是基类接口太对会使得类的结构不清晰不明朗 //delete group; 这个和下面的是等价的,因为base的析构函数是虚函数 delete baseGroup; delete info;}
struct Base { virtual void f() { std::cout << "base\n"; } virtual ~Base() {} virtual void init() {} Base() {}protected: //定义成protected之后,派生类可以访问,外部不可以访问,例子: /* void testBase(){ Base b; 由于析构函数是protected的,因此testBase无法执行这句、 Base* bb = new Base(); 这句跑起来没问题,但是资源释放时会报错 delete bb; 即执行这句的时候,会报错 } */ //但是,将析构函数设置成protected还是有用处的: /* void testBase(){ Derived d; 因为子类可以访问base的析构函数 Derived *dp = new Derived(); 这个也是可以的 delete dp; } */ ~Base() {} }};struct Derived : Base { // 'override' is optional //子类覆盖基类的f虚函数。如果基类没有f函数,则写上override会报错,override可以防止代码的编写错误 void f() override { std::cout << "derived " << m_group.size() << "\n"; } void g() { std::cout << "g\n"; } void init() override { m_group.resize(1000); }private: std::vector m_group;};int main() { Base b; Derived d; // virtual function call through reference Base& br = b; // the type of br is Base& Base& dr = d; // the type of dr is Base& as well br.f(); // prints "base" dr.f(); // prints "derived" // virtual function call through pointer Base* bp = &b; // the type of bp is Base* Base* dp = &d; // the type of dp is Base* as well bp->f(); // prints "base" dp->f(); // prints "derived" // non-virtual function call br.Base::f(); // prints "base" dr.Base::f(); // prints "base"}
参考链接:
1、如果一个类被继承,且基类析构函数不是virtual修饰的,
那么当基类指针或引用指向派生类对象并析构(例如自动对象在函数作用域结束时;或者通过delete)时,会调用基类的析构函数而导致派生类定义的成员没有被析构,产生内存泄露等问题。虽然把析构函数定义成virtual的可以解决这个问题,但是当其它成员函数都不是virtual函数时,会在基类和派生类引入vtable,实例引入vptr造成运行时的性能损失。
如果确定不需要直接而是只通过派生类对象使用基类,可以把析构函数定义为protected(这样会导致基类和派生类外使用自动对象和delete时的错误,因为访问权限禁止调用析构函数),就不会导致以上问题。
2、将构造和析构都声明为protected的用法。
从语法上来讲,一个函数被声明为protected或者private,那么这个函数就不能从“外部”直接被调用了。
通常使用的场景如下:
A)如果你不想让外面的用户直接构造一个类(假设这个类的名字为A)的对象,而希望用户只能构造这个类A的子类
那你就可以将类A的构造函数/析构函数声明为protected,而将类A的子类的构造函数/析构函数声明为public。例如:
class A{ protected: A(){}public: ....};calss B : public A{ public: B(){} ....};A a; // errorB b; // ok
B) 保证对象只生成在堆上
当我们想禁止在栈中产生对象时,如何来实现呢?
例如:
class A{ protected: A() { } ~A() { } public: static A* create() { return new A() ;//调用保护的构造函数 } void destroy() { delete this ;//调用保护的析构函数 }};
我们可以这样来使用它:
A* pa= A::create();pa->destroy() ;
C) 单例模式
class A{private: A(){ } ~A(){ }public: void Instance(){ A a; }};
上面的代码是能通过编译的。上面代码里的Instance函数就是类A的内部的一个函数。Instance函数体里就构建了一个A的对象。但是,这个Instance函数还是不能够被外面调用的。为什么呢?
如果要调用Instance函数,必须有一个对象被构造出来。但是构造函数被声明为private的了。外部不能直接构造一个对象出来。A aObj; // 编译通不过aObj.Instance();
但是,如果Instance是一个static静态函数的话,就可以不需要通过一个对象,而可以直接被调用。如下:
class A{private: A():data(10){ cout << "A" << endl; } ~A(){ cout << "~A" << endl; } public: static A& Instance(){ static A a; return a; } void Print(){ cout << data << endl; }private: int data;};A& ra = A::Instance();ra.Print();
上面的代码其实是设计模式singleton模式的一个简单的C++代码实现。
转载地址:http://yidsn.baihongyu.com/