【问题标题】:How to correctly extend a class in C++ and writing its header file?如何正确扩展 C++ 中的类并编写其头文件?
【发布时间】:2013-09-29 15:03:31
【问题描述】:

我有一个名为person.lib 的第三方库及其标头person.h。这是我的实际项目结构,它可以完美地编译和运行。

实际结构:

ma​​in.cpp

#include <iostream>
#include <time.h>
#include <ctype.h>
#include <string>
#include "person.h"
using namespace person;
using namespace std;

class Client : public Person 
{
    public:
        Client();   
        void onMessage(const char * const);
    private:
        void gen_random(char*, const int);
};

Client::Client() {
    char str[11];
    gen_random(str, 10);
    this->setName(str);
}

void Client::onMessage(const char * const message) throw(Exception &) 
{
    cout << message << endl;
}

void Client::gen_random(char *s, const int len) {
    //THIS FUNCTION GENERATES A RANDOM NAME WITH SPECIFIED LENGTH FOR THE CLIENT
}

int main()
{
    try
    {
        Person *p = new Client;
        p->sayHello();
    }
    catch(Exception &e)
    {
        cout << e.what() << endl;
        return 1;
    }
    return 0;
}

我想通过将Client 类的声明与其定义分开并创建client.hclient.cpp 来重构我的代码。 注意sayHello()onMessage(const * char const)person 库的函数。

重构结构:

ma​​in.cpp

#include <iostream>
#include "client.h"
using namespace person;
using namespace std;

int main()
    {
        try
        {
            Person *p = new Client;
            p->sayHello();
        }
        catch(Exception &e)
        {
            cout << e.what() << endl;
            return 1;
        }
        return 0;
    }

client.cpp

#include "client.h"
using namespace person;
using namespace std;

Client::Client() {
    char str[11];
    gen_random(str, 10);
    this->setName(str);
}

void Client::onMessage(const char * const message) throw(Exception &) 
{
    cout << message << endl;
}

void Client::gen_random(char *s, const int len) {
    //THIS FUNCTION GENERATES A RANDOM NAME WITH SPECIFIED LENGTH FOR THE CLIENT
}

client.h

#ifndef CLIENT_H
#define CLIENT_H
#include <time.h>
#include <ctype.h>
#include <string>
#include "person.h"

class Client : public Person 
{
    public:
        Client();   
        void onMessage(const char * const);
    private:
        void gen_random(char*, const int);
};
#endif

如您所见,我只是创建了一个 client.h,其中包含了基类 person.h,然后我创建了 client.cpp,其中包含了 client.h 和定义的功能。现在,编译给了我这些错误:

error C2504: 'Person': base class undefined     client.h    7   1   Test
error C2440: 'inizialization': unable to convert from 'Client *' to 'person::impl::Person *'   main.cpp 15  1   Test
error C2504: 'Person': base class undefined     client.h    7   1   Test
error C2039: 'setName': is not a member of 'Client'  client.cpp 8   1   Test
error C3861: 'sendMessage': identifier not found    client.cpp  34  1   Test

这只是一个剪切和复制重构,但它不起作用,我真的不明白为什么!解决方案是什么,为什么它会给我这些错误?有什么我缺少的关于 C++ 结构的东西吗?

【问题讨论】:

  • 在重构的标头中包含&lt;person.h&gt;,但在原始代码中是"person.h" 也许链接器没有找到它?
  • @jnovacho 是转录错误,改正后还是一样。
  • client.h 不使用 person 的命名空间。

标签: c++ compilation header


【解决方案1】:

这是一个 dog-n-bird 实现(ruff ruff,cheep cheep) cLawyer 在 main.cpp 中定义和实现,而 cPerson 和 cClient 在自己的头文件中定义,在自己的 cpp 文件中实现。 更好的方法是存储类的名称。然后,不需要重载 speak 方法——只需在每个派生副本中设置 className 即可。但在我的估计中,这对你来说是一个不太有用的例子。

ma​​in.cpp

#include <cstdio>
#include "cClient.h"

class cLawyer : public cPerson
{
    public:
        cLawyer() : cPerson() {}
        ~cLawyer() {}
        void talk(char *sayWhat){printf("cLawyer says: '%s'\n", sayWhat);}
};

int main()
{
    cPerson newPerson;
    cClient newClient;
    cLawyer newLawyer;

    newPerson.talk("Hello world!");
    newClient.talk("Hello world!");
    newLawyer.talk("Hello $$$");

    return 0;
}

cPerson.h

#ifndef cPerson_h_
#define cPerson_h_

class cPerson
{
    public:
        cPerson();
        virtual ~cPerson();
        virtual void talk(char *sayWhat);
    protected:
    private:
};

#endif // cPerson_h_

cPerson.cpp

#include "cPerson.h"
#include <cstdio>
cPerson::cPerson()
{
    //ctor
}

cPerson::~cPerson()
{
    //dtor
}

void cPerson::talk(char *sayWhat)
{
    printf("cPerson says: '%s'\n",sayWhat);
}

cClient.h

#ifndef cClient_h_
#define cClient_h_

#include "cPerson.h"

class cClient : public cPerson
{
    public:
        cClient();
        virtual ~cClient();
        void talk(char *sayWhat);
    protected:
    private:
};

#endif // cClient_h_

cClient.cpp

#include "cClient.h"
#include <cstdio>

cClient::cClient()
{
    //ctor
}

cClient::~cClient()
{
    //dtor
}

输出

cPerson says: 'Hello world!'
cClient says: 'Hello world!'
cLawyer says: 'Hello $$$'

上述建议:

//In the cPerson class, a var
  char *m_className;

//In the cPerson::cPerson constructer, set the var
  m_className = "cPerson";

//Re-jig the cPerson::speak method
void cPerson::speak(char *sayWhat)
{
  printf("%s says: '%s'\n", m_className, sayWhat);
}

// EDIT: *** remove the speak methods from the cClient and cLawyer classes ***

//Initialize the clas name apporpriately in derived classes
//cClient::cClient
  m_className = "cClient";


//Initialize the clas name apporpriately in derived classes
//cLaywer::cLaywer
  m_className = "cLawyer";

【讨论】:

  • 感谢您的回答,我已将我的代码作为第一篇文章进行了修改,但无论如何它都不起作用,同样的错误! 编辑: 我没有 person.cpp。我只有它的标题和 person.lib
  • 不客气。抱歉,您无法将其翻译成适合您的解决方案。您只有 person.lib 和 person.h 文件很好。如果您有编译成的目标代码,则不需要 .cpp 文件。
  • 我的第一篇文章已经更新得很清楚了,也许你能看出问题出在哪里! :)
  • 感谢您的更新。我注意到,您的 client.h 文件中没有包含 using namespace person 声明。也许就是这样?
  • 现在编译!!!但为什么?我已经在 client.cpp 中声明了 using namespace person,正如之前在其他 cmets 中所说,在头文件中不鼓励使用 using 指令。 edit:它可以编译,但不能按预期工作。 onMessage()sayHello() 似乎不是从 Person 继承的。
【解决方案2】:

您将声明类 Client 两次 - 一次在 .h 文件中,一次在 .cpp 中。您只需在.h 文件中声明即可。
您还需要将using namespace person; 放入.h 文件中。
如果 Person 类在 namcespace person 中,请使用 person::Person 访问它。

client.cpp 必须只包含定义!

我认为对于链接器,client.h 中定义的类 Client 和 client.cpp 中定义的类 Client 是不同的类,因此它找不到 Client::Client() 的实现。我的目的是从 client.cpp 中删除类 Client 的声明,只保留函数的定义:

// client.cpp

#include <time.h>
#include <ctype.h>
#include <string>
#include "client.h"
using namespace std;

Client::Client()
{
    //DO STUFF
}

void Client::onMessage(const char * const message)
{
    //DO STUFF
}


void Client::gen_random(char *s, const int len) {
    //DO STUFF
}

【讨论】:

  • using namespace 应避免出现在标题中。
  • 看看编辑过的代码,如果我把 using namespace person 放在 client.h 我有 Error 2 error LNK2019: reference to extern symbol "public: __thiscall Client::Client(void)" (??0Client@@QAE@XZ) not resolved in function _WinMain@16
  • 类人在命名空间person::impl::Person
  • 你的意思是client.cpp
  • @Angelo 这是你的选择:如果成员函数是在类定义中定义的,那么它们就是隐式的inline。缺点是客户端代码对所有成员定义都有编译时依赖性。如果将它们分离到.cpp 文件中,则客户端代码仅具有链接时依赖关系。
猜你喜欢
  • 2021-04-30
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 2012-03-12
相关资源
最近更新 更多