C++抽象类模板构造函数静态成员及MusicPlayer静态方法问题
给定如下C++抽象类模板定义:
template <class MusicPlayer> class SongAbstract { protected: unsigned long unique_id; public: SongAbstract() { static unsigned long counter = 0; unique_id = (counter++); } int play() const { return MusicPlayer::play(this->unique_id); } void stop() const { MusicPlayer::stop(); } unsigned long get_id() const { return unique_id; } protected: virtual void print_info(ostream& os) const = 0; };
考题要求:根据上述代码实现MusicPlayer类,编写名为AndroidMusicPlayer的类声明使程序可正常运行。
官方给出的解决方案如下:
class AndroidMusicPlayer { public: static int play(unsigned long id); static void stop(); };
针对第一个疑问:抽象类模板构造函数内部定义静态数据成员的作用是什么?
构造函数内的static unsigned long counter是函数级静态变量,程序运行期间只会在第一次执行该构造函数时初始化一次,后续所有构造函数调用都会复用同一个counter变量。它的作用就是给每个创建的SongAbstract派生类对象分配全局唯一的unique_id标识,保证同系列歌曲对象不会出现ID重复的情况。这种写法不需要额外在类外声明全局计数变量或者类静态成员,封装性更优。另外需要注意,因为是类模板,不同MusicPlayer类型参数对应的SongAbstract实例会各自维护独立的counter,比如AndroidMusicPlayer对应的歌曲对象和IOSMusicPlayer对应的歌曲对象,计数是相互独立的。针对第二个疑问:AndroidMusicPlayer中的方法为什么要声明为static?它们访问的unique_id成员并不是静态的。
首先看SongAbstract里的调用写法MusicPlayer::play(this->unique_id),这是C++调用静态类成员的标准语法,不需要创建MusicPlayer类的实例就能直接调用,所以要求对应的方法必须是静态的。
另外你混淆了成员的访问逻辑:unique_id确实是SongAbstract对象的非静态成员,但它是作为入参传递给MusicPlayer::play方法的,不是MusicPlayer的方法直接访问SongAbstract的成员,所以两者的静态属性没有对应关系。
这种设计也符合播放器的通用业务逻辑:整个系统只需要一个全局的播放器实例,所有歌曲的播放、停止控制都走同一个播放器处理,不需要每首歌单独创建播放器对象。
内容的提问来源于stack exchange,提问作者GalMichaeli

