structNumber { typedefint value_type; int n; voidset(int v){ n = v; } intget()const{ return n; } };
template <typename BASE, typename T = typename BASE::value_type> struct Undoable : public BASE { typedef T value_type; T before; voidset(T v){ before = BASE::get(); BASE::set(v); } voidundo(){ BASE::set(before); } };
template <typename BASE, typename T = typename BASE::value_type> struct Redoable : public BASE { typedef T value_type; T after; voidset(T v){ after = v; BASE::set(v); } voidredo(){ BASE::set(after); } };
// abstract base class which implements Execute() and provides logging feature. Derived classes must implement OnExecute(). classBaseLoggingTask : public ITask { public: voidExecute()override{ std::cout << "LOG: The task is starting - " << GetName() << std::endl; OnExecute(); std::cout << "LOG: The task has completed - " << GetName() << std::endl; } virtualvoidOnExecute()= 0; }; // Concrete Task implementation that reuses the logging code of the BaseLoggingTask classMyTask : public BaseLoggingTask { public: voidOnExecute()override{ std::cout << "...This is where the task is executed..." << std::endl; } std::string GetName()override{ return"My task name"; } };
// MyTask is written with no coupling to the reusable logging and timing task classMyTask : public ITask { public: voidExecute()override{ std::cout << "...This is where the task is executed..." << std::endl; } std::string GetName()override{ return"My task name"; } }; // Add timing and logging to MyTask through composition and delegation std::unique_ptr<Itask> t(new LoggingTask(new TimingTask(new MyTask()))); t->Execute();
// A plain old MyTask MyTask t1; t1.execute(); // A MyTask with added timing: TimingTask<MyTask> t2; t2.Execute(); // A MyTask with added logging and timing: LoggingTask<TimingTask<MyTask>> t3; t3.Execute(); // A MyTask with added logging and timing written to look a bit like the composition example typedef LoggingTask<TimingTask<MyTask>> Task; Task t4; t4.Execute();
template <typename T> classTaskAdapter : public ITask, public T { public: voidExecute()override{ T::Execute(); } std::string GetName()override{ return T::GetName(); } };
// typedef for our final class, inlcuding the TaskAdaTpter<> mixin typedef TaskAdapter<LoggingTask<TimingTask<MyTask>>> ask; // instance of our Task - note that we are not forced into any heap allocations! Task t; // implicit conversion to ITask* thanks to the TaskAdapter<> ITask* it = &t; it->Execute();
classCustomer { public: Customer(constchar* fn, constchar* ln) : mFirstName(fn), mLastName(ln) {} voidPrint()const{ cout << mFirstName << ' ' << mLastName; } private: constchar* mFirstName, constchar* mLastName; }; // The new mixin class will be defined using multiple inheritance. // Therefore Base must be turned into a virtual base class. template <typename Base> classPhoneContact: virtualpublic Base { public: PhoneContact(constchar* fn, constchar* ln, constchar* pn) :Base(fn, ln), mPhone(pn) {} voidPrint()const{ Base::Print(); BasicPrint(); } protected: // We need an "inner" print method that prints the PhoneContact-specific // information only. voidBasicPrint()const{ cout << ' ' << mPhone; } private: constchar* mPhone; }; // Base has to be declared as virtual base class here, too. template <typename Base> classEmailContact: virtualpublic Base { public: EmailContact(constchar* fn, constchar* ln, constchar* e) : Base(fn, ln), mEmail(e){} voidPrint()const{ Base::Print(); BasicPrint(); } protected: // We need an "inner" print method that prints the EmailContact-specific // information only. voidBasicPrint()const{ cout << ' ' << mEmail; } private: constchar* mEmail; }; template <typename Base> classPhoneAndEmailContact : public PhoneContact<Base>, public EmailContact<Base> { public: // Because Base is a virtual base class, PhoneAndEmailContact is now // responsible for its initialization. PhoneAndEmailContact(constchar* fn, constchar* ln, char* pn, constchar* e) : PhoneContact<Base>(fn, ln, pn) , EmailContact<Base>(fn, ln, e) , Base(fn, ln) {} voidPrint()const{ Base::Print(); PhoneContact<Base>::BasicPrint(); EmailContact<Base>::BasicPrint(); } };
// Define special intialization methods in each class and no longer rely // on the proper initialization though constructors. classCustomer { public: // Initialization method for Customer. // A default constructor will be generated automatically. voidinit(constchar* fn, constchar* ln){ mFirstName = fn; mLastName = ln; } voidPrint()const{ cout << mFirstName << ' ' << mLastName; } private: constchar* mFirstName, constchar* mLastName; }; template <typename Base> classPhoneContact: public Base { public: // Initialization method for PhoneContact only. // A default constructor will be generated automatically. voidinit(constchar* pn){ mPhone = pn; }
voidPrint()const{ Base::Print(); cout << ' ' << mPhone; } private: constchar* mPhone; }; template <typename Base> classEmailContact: public Base { public: // Initialization method for EmailContact only. // A default constructor will be generated automatically. voidinit(constchar* e){ mEmail = e; }
Counter() { ++mObjectsCreated; ++mObjectsAlive; } Counter(const Counter&) { ++mObjectsCreated; ++mObjectsAlive; } protected: // objects should never be removed through pointers of this type ~Counter() { --mObjectsAlive; } }; template <typename T> int Counter<T>::mObjectsCreated(0); template <typename T> int Counter<T>::mObjectsAlive(0);
当发生派生类到基类对象的复制时,很重要的事情就是保证基类对象的虚表指针指向正确的虚表。对于Base b = Derived()这种情况,我们知道其中发生Slicing,即只有Derived对象中的基类子对象复制给了b。但其中编译器还会正确地设置虚表指针,保证这样构造出来的b的虚表指针指向的是Base的虚表,而不是Derived的虚表。
树莓派的一个很酷的特点就是,它的开发环境不像过去的嵌入式系统那样,它上面跑的就是正常的Linux,还包括各种Debian系的工具。简单地说在树莓派上适配Redis不算很困难。Linux程序移植到树莓派上最常见的问题就是性能或内存占用不匹配,但在Redis上这不是问题,因为它本身就被设计为:空实例只占用1MB内存,且查询请求会走内存,因此它足够快,也不会给闪存太高的压力,而且在需要持久化时,它只会用AOF(Append Only File)。但树莓派上用的是ARM处理器,意味着我们要小心处理未对齐的内存访问。
virtualvoidFunc(){ a += 1; b -= 1; c *= 2; printf("a:%d b:%ld c:%d\n", a, b, c); } };
对应的main函数不变,直接运行会报错:
1 2 3 4 5
struct.cpp: In function ‘int main()’: struct.cpp:18:19: error: in C++98 ‘s’ must be initialized by constructor, not by ‘{...}’ S s = {1, 2, 3}; ^ struct.cpp:18:19: error: could not convert ‘{1, 2, 3}’ from ‘<brace-enclosed initializer list>’ to ‘S’
似乎此时struct与c的struct已经不一样了。我们给它加上一个构造函数:
1 2 3 4 5
S::S(int8_t x, int64_t y, int32_t z) { a = x; b = y; c = z; }
structBase { int8_t ba; }; structC: publicvirtual Base { int32_t ca; }; structD: publicvirtual Base { int32_t da; }; structS: public C, public D { int64_t b; int32_t c; };