信号槽的C++实现 (SetWatch RemoveWatch的原型和使用)
来源: 钟英杰/
华南师范大学
820
3
0
2017-04-19

        信号槽的实现并不复杂,如果了解观察者模式加上标准模板去实现并不难,方法也很多,我现在提供一种现实方法,供参考(版权所有,引用请说明出处)。

头文件:

call.h

//////////////////

#pragma once

#include <vector>


using namespace std;


template<class RT>

class ReturnType

{

public:

typedef RT T;

};


//////////////////////////////////////////////////////////////////////////

//to take the right work for 64 bit data pointers

class CallID

{

public:

CallID();

CallID(void* pObject, void* pPfn);

CallID(const CallID& rSrc);


virtual void operator=(const CallID& rSrc);

virtual bool operator==(const CallID& rSrc) const;

virtual bool operator!=(const CallID& rSrc) const;


protected:

void* m_pObject,

* m_pPfn;

};


//////////////////////////////////////////////////////////////////////////

//ICallHandleImp Declaration


class ICallHandleImp

{

public:

//operator

static void* operator new(size_t nSize);

static void operator delete(void* p);

protected:

//operator

ICallHandleImp &operator= (const ICallHandleImp&);

};


//////////////////////////////////////////////////////////////////////////

//CallHandleImp<ICALLSTUB> Declaration


template<class ICALLSTUB>

class CallHandleImp :public ICallHandleImp

{

public:

//Status

CallID GetID()const;


//Implementation

ICALLSTUB* Attch(ICALLSTUB* pCallStub);

void Detach();


long GetRef() const;//*m_pCallStub's reference count.


protected:

//construction/destruction

CallHandleImp(ICALLSTUB* pCallStub);

//SmartPtr<ICALLSTUB> m_pCallStub;

ICALLSTUB* m_pCallStub;

};


//Declaration and Implementation of the helper class-template Equal ID cmd.

template<typename Handle>

class EqualIdCmd

{

public:

EqualIdCmd(CallID nID):m_nID(nID){};

~EqualIdCmd(){};


bool operator()(void* pVoid)

{

Handle* pCH = (Handle*)pVoid;

return (pCH->GetID() == m_nID);

}


private:

CallID m_nID;

};

//////////////////////////////////////////////////////////////////////////

//EventImp Declaration


template<class CALLHANDLE>

class EventImp

{

public:

const CALLHANDLE& SetWatch(const CALLHANDLE& rCallHandle);


bool RemoveWatch(const CALLHANDLE& rCallHandle);


bool RemoveWatch(const CallID& rCallID);


void RemoveAll();


bool IsEmpty() const;

protected:

EventImp();

EventImp(const EventImp& rEventImp);

~EventImp();


//operators

EventImp& operator =(const EventImp& rEventImp);


//Attributes

std::vector<CALLHANDLE* > m_rgpCallHandles;

};


//////////////////////////////////////////////////////////////////////////

//ICallStubImp Declaration


class ICallStubImp

{

public:

//status

virtual CallID GetID() const = 0;


//Implementation

long GetRef() const;

long AddRef();

long Release();


protected:

ICallStubImp();

ICallStubImp(const ICallStubImp& rCallStubImp);


virtual ~ICallStubImp();


ICallStubImp& operator =(const ICallStubImp& rCallStubImp);


private:

// attributes

long m_lRefCount;

};


//////////////////////////////////////////////////////////////////////////

// ICallStub0< RT> Declaration


template<class RT>

class ICallStub0 : public ICallStubImp

{


public:

typedef typename ReturnType<RT>::T Ret_t;

virtual Ret_t operator()() const = 0;

};


//////////////////////////////////////////////////////////////////////////

// ICallStub1< RT> Declaration


template<class RT, class AT1>

class ICallStub1 : public ICallStubImp

{


public:

typedef typename ReturnType<RT>::T Ret_t;

virtual Ret_t operator()(AT1 agr1) const = 0;

};


//////////////////////////////////////////////////////////////////////////

//CallStubImp<ICALSTUB, CALL> Declaration


template<class ICALLSTUB, class CALL >

class CallStubImp : public ICALLSTUB 

{

public:

//status

virtual CallID GetID() const;


protected:

CallStubImp(const CALL& rCall);

//attributes

CALL m_Call;

};


//////////////////////////////////////////////////////////////////////////

//CallStub1 < RT, AT1, CALL1 > Declaration


template<class RT, class AT1, class CALL1 >

class CallStub1 : public CallStubImp< ICallStub1 < RT, AT1>, CALL1 > 

{

public:

CallStub1(const CALL1& rCall);


//operators

typedef typename ReturnType<RT>::T Ret_t;

virtual Ret_t operator()(AT1 arg1) const;

};


//////////////////////////////////////////////////////////////////////////

//FunctionImp Declaration


template<class FUNCTION_PTR>

class FunctionImp

{

public:

CallID GetID() const;


protected:

//type

typedef FUNCTION_PTR FUNCTION_PTR;


FunctionImp(FUNCTION_PTR pfn);


//attributes

FUNCTION_PTR m_pfn;

};


//////////////////////////////////////////////////////////////////////////

//function1 declaration


template<class RT, class AT1>

class Function1 : public FunctionImp< RT(*)(AT1) >

{

public:

Function1(FUNCTION_PTR pfn);


//operators

typedef typename ReturnType<RT>::T Ret_t;

Ret_t operator()(AT1 arg1) const;

};


//////////////////////////////////////////////////////////////////////////

//MethodImp Declaration


template<class CLASS, class METHOD_PTR>

class MethodImp

{

public:

//status

CallID GetID() const;

protected:

//type

typedef METHOD_PTR METHOD_PTR;


MethodImp(CLASS* pObject, METHOD_PTR pmfn);


//attributes

CLASS* m_pObject;

METHOD_PTR m_pmfn;

};


//////////////////////////////////////////////////////////////////////////

//IgnoreImp Declaration


template<class CALL>

class IgnoreImp

{

public:

//status

CallID GetID() const;


protected:

IgnoreImp(const CALL& rCall);


//attributes

CALL m_Call;

};


//////////////////////////////////////////////////////////////////////////

//Ignore1Stof1 Declaration


template<class RT, class AT1, class CALL0>

class Ignore1Stof1 : public IgnoreImp< CALL0>

{

public:

Ignore1Stof1(const CALL0& rCall0);


//operators

typedef typename ReturnType<RT>::T Ret_t;

Ret_t operator ()(AT1 arg1) const;


};


//////////////////////////////////////////////////////////////////////////

//Method1 Declaration


template<class RT, class CLASS, class AT1>

class Method1 : public MethodImp <CLASS, RT(CLASS::*)(AT1) >

{

public:

Method1(CLASS* pObject, METHOD_PTR pmfn);


//operators

typedef typename ReturnType<RT>::T Ret_t;

Ret_t operator ()(AT1 arg1) const;

};


//////////////////////////////////////////////////////////////////////////

//CallHandle1<RT, AT1> Declaration


template<class RT, class AT1>

class CallHandle1 : public CallHandleImp< ICallStub1<RT, AT1>>

{

public:

CallHandle1(ICallStub1<RT, AT1>* pCallStub = nullptr);


//operators

typedef typename ReturnType<RT>::T Ret_t;

Ret_t operator ()(AT1 arg1) const;

};


//////////////////////////////////////////////////////////////////////////

//Event1 Declaration


template<class AT1>

class Event1 : public EventImp< CallHandle1< void, AT1> >

{

public:

//operators

void operator ()(AT1 arg1) const;

};


//////////////////////////////////////////////////////////////////////////

//Several Helper Macros and Functions


#define CALL_INTERFACE_DECL_0( RT )const ICallStub0< RT >*

#define CALL_INTERFACE_DECL_1( RT, AT1 )const ICallStub1<  RT, AT1 >*

#define CALL_INTERFACE_DECL_2( RT, AT1, AT2 )const ICallStub2< RT, AT1, AT2 >*

#define CALL_INTERFACE_DECL_3( RT, AT1, AT2, AT3 )const ICallStub3<  RT, AT1, AT2, AT3 >*


#define CALL_INTERFACE_0( RT )( ( const ICallStub0< RT >*) nullptr)

#define CALL_INTERFACE_1( RT, AT1 )( ( const ICallStub1<  RT, AT1 >*)  nullptr )

#define CALL_INTERFACE_2( RT, AT1, AT2 )( ( const ICallStub2< RT, AT1, AT2 >*)  nullptr)

#define CALL_INTERFACE_3( RT, AT1, AT2, AT3 )( ( const ICallStub3<  RT, AT1, AT2, AT3 >*) nullptr )


#define Function( pfn )__Function(pfn)

#define Method( pObject, pmfn)__Method(pObject, pmfn)



#define  MakeFunction0Function

#define  MakeFunction1Function

#define  MakeFunction2Function

#define  MakeFunction3Function


#define MakeMethod0Method

#define MakeMethod1Method

#define MakeMethod2Method

#define MakeMethod3Method



#define BindFirst__BindFirst( rCall, rArg, GetCallInterface( rCall))

#define BindSecond__BindSecond( rCall, rArg, GetCallInterface( rCall))

#define BindThird__BindThird( rCall, rArg, GetCallInterface( rCall))


#define ConverRetVal( rCall, rConverter)__ConverRetval( rCall, rConverter, GetCallInterface( rCall), GetCallInterface( rConverter))

#define ConverFirst( rCall, rConverter)__ConverFirst( rCall, rConverter, GetCallInterface( rCall), GetCallInterface( rConverter))

#define ConverSecond( rCall, rConverter)__ConverSecond( rCall, rConverter, GetCallInterface( rCall), GetCallInterface( rConverter))

#define ConverThird( rCall, rConverter)__ConverThird( rCall, rConverter, GetCallInterface( rCall), GetCallInterface( rConverter))


#define Expression( rCall0)__Expression(rCall0, GetCallInterface( rCall0))



#include "call.inl"

//////////////////call.inl////////////////////////////////

#include "call.h"

#include <algorithm>


//////////////////////////////////////////////////////////////////////////

//CallStubImp<ICALLSTUB, CALL> Implementation


template<class ICALLSTUB, class CALL >

inline CallStubImp< ICALLSTUB, CALL>::CallStubImp(const CALL& rCall)

:m_Call(rCall)

{

}


//status

template<class ICALLSTUB, class CALL >

inline CallID CallStubImp< ICALLSTUB, CALL>::GetID() const

{

return m_Call.GetID();

}


//////////////////////////////////////////////////////////////////////////

//CallStub1<RT, AT1, CALL1> Implementation


template<class RT, class AT1, class CALL1>

inline CallStub1<RT, AT1, CALL1>::CallStub1(const CALL1& rCall1)

:CallStubImp< ICallStub1< RT, AT1>, CALL1 >(rCall1)

{

}


//operators

template<class RT, class AT1, class CALL1>

inline typename ReturnType<RT>::T CallStub1< RT, AT1, CALL1>::operator()(AT1 arg1) const

{

return m_Call(arg1);

}


//////////////////////////////////////////////////////////////////////////

//EventImp Implementation


template< class CALLHANDLE >

inline EventImp< CALLHANDLE>::EventImp()

{

}


template< class CALLHANDLE >

inline EventImp< CALLHANDLE>::EventImp(const EventImp&)

{

}


template< class CALLHANDLE >

inline EventImp< CALLHANDLE>::~EventImp()

{

RemoveAll();

}


//operators

template< class CALLHANDLE >

inline EventImp< CALLHANDLE>& EventImp <CALLHANDLE>::operator =(const EventImp&)

{

return *this;

}


//Implementation

template< class CALLHANDLE >

inline const CALLHANDLE& EventImp< CALLHANDLE>::SetWatch(const CALLHANDLE& rCallHandle)

{

CALLHANDLE* pNew = new CALLHANDLE(rCallHandle);

m_rgpCallHandles.push_back(pNew);


return *pNew;

}


template< class CALLHANDLE >

inline bool EventImp< CALLHANDLE>::RemoveWatch(const CALLHANDLE& rCallHandle)

{

return RemoveWatch(rCallHandle.GetID());

}


template< class CALLHANDLE >

inline bool EventImp< CALLHANDLE>::RemoveWatch(const CallID& rCallID)

{

std::vector< CALLHANDLE*>::iterator end = m_rgpCallHandles.end();

EqualIdCmd<CALLHANDLE> cmd(rCallID);

std::vector<CALLHANDLE*>::iterator iter = std::find(m_rgpCallHandles.begin(), end, cmd);

if (iter != end)

{

CALLHANDLE* pCH = *iter;

m_rgpCallHandles.erase(iter);

delete pCH;


return true;

}


return false;

}


template< class CALLHANDLE >

inline void EventImp< CALLHANDLE>::RemoveAll()

{

int nSize = (int)m_rgpCallHandles.size();

for (int i = 0; i < nSize; ++i)

{

delete m_rgpCallHandles[i];

}


m_rgpCallHandles.clear();

}


template< class CALLHANDLE >

inline bool EventImp< CALLHANDLE>::IsEmpty() const

{

return m_rgpCallHandles.size() == 0;

}


template< class CALLHANDLE >

void CopyCallIDs(const std::vector<CALLHANDLE*>& m_rgpCallHandles, std::vector< CallID>& rgpCallIDs)

{

rgpCallIDs.reserve(m_rgpCallHandles.size());


std::vector< CALLHANDLE*>::const_iterator iter = m_rgpCallHandles.begin();

std::vector< CALLHANDLE*>::const_iterator end = m_rgpCallHandles.end();


for (; iter != end; ++iter)

{

CALLHANDLE* pCH = *iter;

rgpCallIDs.push_back(pCH->GetID());

}

}


//////////////////////////////////////////////////////////////////////////

//MethodImp Implementation


template< class CLASS, class METHOD_PTR >

inline MethodImp< CLASS, METHOD_PTR>::MethodImp(CLASS* pObject, METHOD_PTR pmfn)

:m_pObject(pObject)

,m_pmfn(pmfn)

{

}


//status

template < class CLASS, class METHOD_PTR >

inline CallID MethodImp< CLASS, METHOD_PTR>::GetID() const

{

return CallID((void*)m_pObject, *((void**)&m_pmfn));


}


//////////////////////////////////////////////////////////////////////////

//Method Implementation


template<class RT, class CLASS, class AT1 >

inline Method1<RT, CLASS, AT1 >::Method1(CLASS* pObject, METHOD_PTR pmfn)

:MethodImp< CLASS, METHOD_PTR>(pObject, pmfn)

{

}


#pragma warning(push)

#pragma warning(disable : 4701)


//operators

template<class RT, class CLASS, class AT1 >

inline typename ReturnType<RT>::T Method1< RT, CLASS, AT1>::operator()(AT1 arg1) const

{

typedef ReturnType<RT>::T(CLASS::*Method)(AT1);

return (m_pObject->*((Method)m_pmfn))(arg1);

}


#pragma warning( pop)


//////////////////////////////////////////////////////////////////////////

//IgnoreImp Implementation


template< class CALL >

inline IgnoreImp< CALL >::IgnoreImp(const CALL& rCall)

:m_Call(rc)

{

}


//status

template< class CALL >

inline CallID IgnoreImp< CALL >::GetID() const

{

return m_Call.GetID();

}


//////////////////////////////////////////////////////////////////////////

//CallHandleImp< ICALLSTUB > Implementation


template<class ICALLSTUB >

inline CallHandleImp< ICALLSTUB>::CallHandleImp(ICALLSTUB* pCallStub)

:m_pCallStub(pCallStub)

{

}


//status

template<class ICALLSTUB >

inline CallID CallHandleImp< ICALLSTUB >::GetID() const

{

return m_pCallStub->GetID();

}


//Implementation

template<class ICALLSTUB >

inline ICALLSTUB* CallHandleImp< ICALLSTUB >::Attch(ICALLSTUB* pCallStub)

{

m_pCallStub = pCallStub;

return pCallStub;

}


template<class ICALLSTUB >

inline void CallHandleImp< ICALLSTUB >::Detach()

{

m_pCallStub = nullptr;

}


template<class ICALLSTUB >

inline long CallHandleImp< ICALLSTUB >::GetRef() const

{

if (m_pCallStub == nullptr)

{

return 0;

}


return m_pCallStub->GetRef();

}


//////////////////////////////////////////////////////////////////////////

//CallHandle1< RT, AT1 > Implementation


template< class RT, class AT1 >

inline CallHandle1< RT, AT1>::CallHandle1(ICallStub1 <RT, AT1>* pCallStub)

:CallHandleImp< ICallStub1< RT, AT1 > >(pCallStub)

{


}


//operators

template< class RT, class AT1>

inline typename ReturnType<RT>::T CallHandle1< RT, AT1 >::operator()(AT1 arg1) const

{

return (*m_pCallStub)(arg1);

}


//////////////////////////////////////////////////////////////////////////

//Event1 Implementation

//operators


template<class AT1>

inline void Event1< AT1 >::operator()(AT1 arg1) const

{

typedef CallHandle1< void, AT1 > CALLHANDLE;


if (!m_rgpCallHandles.empty())

{

//create snapshot of call-ids

std::vector< CallID> rgpCallIDs;

CopyCallIDs<CALLHANDLE>(m_rgpCallHandles, rgpCallIDs);


//notify

for (std::vector<CallID>::size_type i = 0; i < rgpCallIDs.size(); i++)

{

std::vector<CALLHANDLE*> ::const_iterator end = m_rgpCallHandles.end();

EqualIdCmd< CALLHANDLE > cmd(rgpCallIDs[i]);

std::vector< CALLHANDLE*>::const_iterator iter = std::find_if(m_rgpCallHandles.begin(), end, cmd);

if (iter != end)

{

CALLHANDLE* pCH = *iter;

(*pCH)(arg1);

}

}

}

}


//////////////////////////////////////////////////////////////////////////

//Determining Call-Interface


void GetCallInterface();

//function1

template< class RT, class AT1 >

inline CALL_INTERFACE_DECL_1(RT, AT1) GetCallInterface(const Function1< RT,AT1>& )

{

return nullptr;

}


//Method1

template< class RT, class CLASS, class AT1 >

inline CALL_INTERFACE_DECL_1(RT, AT1) GetCallInterface(const Method1< RT, CLASS, AT1 >&)

{

return nullptr;

}


//////////////////////////////////////////////////////////////////////////

//CallStub Helpers Impleemntation


void __CreateCallStub();

//Call0 -> CallStub1

template< class CALL0, class RT, class CS_RT, class CS_AT1 >

inline CallStub1< CS_RT, CS_AT1,

Ignore1Stof1< CS_RT, CS_AT1, CALL0 > >* __CreateCallStub(const CALL0& rCall0,

CALL_INTERFACE_DECL_1(CS_RT, CS_AT1), 

CALL_INTERFACE_DECL_0(RT))

{

typedef Ignore1Stof1< CS_RT, CS_AT1, CALL0> CALL1;

typedef CallStub1 <CS_RT, CS_AT1, CALL1 > CALLSTUB1;


return new CALLSTUB1(CALL1(rCall0));

}


//Call1->CallStub1

template< class CALL1, class RT, class AT1, class CS_RT, class CS_AT1 >

inline CallStub1< CS_RT, CS_AT1, CALL1 >* __CreateCallStub(const CALL1& rCall1, 

  CALL_INTERFACE_DECL_1(CS_RT, CS_AT1), 

  CALL_INTERFACE_DECL_1(RT, AT1))

{

typedef CallStub1< CS_RT, CS_AT1, CALL1> CALLSTUB1;

return new CALLSTUB1(rCall1);

}


//////////////////////////////////////////////////////////////////////////

//Determining CreateCallStub-Interface

void CreateCallStub();


//Any Call->CallStub1

template< class CALL, class RT, class AT1>

inline ICallStub1< RT, AT1 >* CreateCallStub(const CALL& rCall, 

CALL_INTERFACE_DECL_1(RT, AT1) CallStubInterface)

{

return __CreateCallStub(rCall, CallStubInterface, GetCallInterface(rCall));

}


//////////////////////////////////////////////////////////////////////////

//CallHandle Helpers Implementation


void CreateCallHandle();

//Any Call->CallHandle1

template< class CALL, class RT, class AT1>

inline CallHandle1< RT, AT1 > CreateCallHandle(const CALL& rCall, 

  CALL_INTERFACE_DECL_1(RT, AT1) CallHandleInterface)

{

return CreateCallStub(rCall, CallHandleInterface);

}


//////////////////////////////////////////////////////////////////////////

//SetWatch/RemoveWatch Implementation


template< class AT1, class CALL>

inline const CallHandle1< void, AT1 >& SetWatch(Event1< AT1 >& rEvent1, const CALL& rCall)

{

return rEvent1.SetWatch(CreateCallHandle(rCall, CALL_INTERFACE_1(void, AT1)));

}


template<class EVENT, class CALL >

inline bool RemoveWatch(EVENT& rEvent, const CALL& rCall)

{

return rEvent.RemoveWatch(rCall.GetID());

}


void __Function();


template< class RT, class AT1 >

inline Function1<RT, AT1> __Function(RT(*pfn)(AT1))

{

return pfn;

}


void __Method();


template< class RT, class METHOD_CLASS, class AT1, class OBJECT_CLASS >

inline Method1< RT, METHOD_CLASS, AT1 > __Method(OBJECT_CLASS* pObject, 

RT(METHOD_CLASS::*pmfn)(AT1) const)

{

typedef RT(METHOD_CLASS::*NonConstMethod)(AT1);


return Method1< RT, METHOD_CLASS, AT1 >(pObject, (NonConstMethod)pmfn);

}


template< class RT, class METHOD_CLASS, class AT1, class OBJECT_CLASS >

inline Method1< RT, METHOD_CLASS, AT1 > __Method(OBJECT_CLASS* pObject, RT(METHOD_CLASS::*pmfn)(AT1))

{

return Method1<RT, METHOD_CLASS, AT1 >(pObject, pmfn);

}

///////////////////////////call.cpp///////////////////////////////////////////

#include "stdafx.h"

#include "call.h"


#include <wtypes.h>


//////////////////////////////////////////////////////////////////////////

//Due to the lack of an __int64 data type we need a class CallID

CallID::CallID()

:m_pObject(nullptr)

,m_pPfn(nullptr)

{

}


CallID::CallID(void* pObject, void* pPfn)

:m_pObject(pObject)

,m_pPfn(pPfn)

{

}


CallID::CallID(const CallID& rSrc)

:m_pObject(rSrc.m_pObject)

,m_pPfn(rSrc.m_pPfn)

{

}


void CallID::operator=(const CallID& rSrc)

{

m_pObject = rSrc.m_pObject;

m_pPfn    = rSrc.m_pPfn;

}


bool CallID::operator==(const CallID& rSrc) const

{

if (m_pObject != rSrc.m_pObject)

return false;


if (m_pPfn != rSrc.m_pPfn)

return false;


return true;

}


bool CallID::operator!=(const CallID& rSrc) const

{

if (m_pObject != rSrc.m_pObject)

return true;


if (m_pPfn != rSrc.m_pPfn)

return true;


return false;

}


//////////////////////////////////////////////////////////////////////////

//ICallStubImp Implementation


ICallStubImp::ICallStubImp()

:m_lRefCount(0)

{

}


ICallStubImp::ICallStubImp(const ICallStubImp& )

:m_lRefCount(0)

{

}


ICallStubImp::~ICallStubImp()

{

}


//Implementation

long ICallStubImp::GetRef() const

{

return m_lRefCount;

}


long ICallStubImp::AddRef()

{

return ++m_lRefCount;

}


long ICallStubImp::Release()

{

long lRefCount = --m_lRefCount;


if (lRefCount < 0)

{

delete this;

}


return lRefCount;

}


//////////////////////////////////////////////////////////////////////////

//ICallHandleImp Implementation


void* ICallHandleImp::operator new(size_t nSize)

{

return ::operator new(nSize);

}


void ICallHandleImp::operator delete(void* p)

{

::operator delete(p);

}


ICallHandleImp& ICallHandleImp::operator =(const ICallHandleImp& )

{

return *this;

}


///////////////////////////////测试////////////////////////////////////

// SetWatch.cpp : Defines the entry point for the console application.

//


#include "stdafx.h"

#include "call.h"


class Action

{

public:

Action(){}

~Action(){}


void MyAction()

{

m_Event(10);

}


public:

Event1<int> m_Event;

};


class Response

{

public:

Response(Action* pAct)

:m_pAct(pAct)

{

SetWatch(m_pAct->m_Event, MakeMethod1(this, &Response::ShowInfo));

}

~Response(){};


public:

void ShowInfo(int nData)

{

printf("call ShowInfo nData = %d", nData);

}

private:

Action* m_pAct;

};



int _tmain(int argc, _TCHAR* argv[])

{

Action act;

Response res(&act);


act.MyAction();

getchar();

return 0;

}

代码很多,以后有时间会多加点注释和分析。


登录用户可以查看和发表评论, 请前往  登录 或  注册
SCHOLAT.com 学者网
免责声明 | 关于我们 | 联系我们
联系我们: