如何在 C++ 中正确扩展类并编写其头文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19079534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to correctly extend a class in C++ and writing its header file?
提问by Angelo
Note: I've edited my old question to be as clear as possible.
注意:我已经编辑了我的旧问题,使其尽可能清晰。
I've got a third party library named person.lib
and its header person.h
. This is my actual project structure and it compiles and runs perfectly.
我有一个名为的第三方库person.lib
及其 header person.h
。这是我的实际项目结构,它可以完美地编译和运行。
Actual Structure:
实际结构:
main.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;
}
Now, I want to refactor my code by dividing the declaration of my Client
class from its definition and create client.h
and client.cpp
. PAY ATTENTION: sayHello()
and onMessage(const * char const)
are functions of the person library.
现在,我想通过将我的Client
类的声明与其定义分开来重构我的代码并创建client.h
和client.cpp
。注意:sayHello()
和onMessage(const * char const)
是人库的功能。
Refactored Structure:
重构结构:
main.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
客户端.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
As you can see, I've simply created a client.h
in wich there's the inclusion of the base class person.h
, then I've created client.cpp
in wich there's the inclusion of client.h
and the definitions of its functions. Now, the compilation gives me these errors:
正如您所看到的,我只是在其中创建了一个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
It's a merely cut© refactoring but it doesn't work and I really don't understand WHY! What's the solution and why it gives me these errors? Is there something about C++ structure that I'm missing? Thank you.
这只是一个简单的剪切和复制重构,但它不起作用,我真的不明白为什么!解决方案是什么,为什么会出现这些错误?有没有我遗漏的关于 C++ 结构的东西?谢谢你。
回答by enhzflep
Here's a dog-n-bird implementation (ruff ruff, cheep cheep) cLawyer is defined and implemented in main.cpp, while cPerson and cClient are defined in their own header files, implemented in their own cpp file. A better approach would store the name of the class. Then, one wouldn't need to overload the speak method - one could simply set the className in each derived copy. But that would have provided in my estimates, a less useful example for you.
这里是dog-n-bird的实现(ruff ruff, cheep cheep)cLawyer是在main.cpp中定义和实现的,而cPerson和cClient是在自己的头文件中定义的,在自己的cpp文件中实现。更好的方法是存储类的名称。然后,就不需要重载 speak 方法 - 只需在每个派生副本中设置 className 即可。但这会在我的估计中提供,对您来说是一个不太有用的例子。
main.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
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
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
客户端.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
客户端.cpp
#include "cClient.h"
#include <cstdio>
cClient::cClient()
{
//ctor
}
cClient::~cClient()
{
//dtor
}
Output
输出
cPerson says: 'Hello world!'
cClient says: 'Hello world!'
cLawyer says: 'Hello $$$'
Suggestions noted above:
上面提到的建议:
//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";
回答by Shimon Rachlenko
You are declaring the class Client twice - once in the .h
file and once in .cpp
. You only need to declare it in the .h
file.You also need to put the using namespace person;
to the .h
file.
If class Person is in namcespace person, use the person::Person
to access it.
您将类 Client 声明两次 - 一次在.h
文件中,一次在.cpp
. 你只需要在.h
文件中声明它。你也需要把using namespace person;
该.h
文件。
如果类 Person 在名称空间中,则使用person::Person
来访问它。
The client.cpp
must contain definitions only!
在client.cpp
只能包含定义!
I think for the linker the class Client defined in client.h and class Client defined in client.cpp are different classes, thus it cannot find the implementation of Client::Client(). I purpose to remove the declaration of class Client from the client.cpp and leave there only definitions of functions:
我认为对于链接器,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
}