![](/img/trans.png)
[英]Java 8 times faster with arrays than std::vector in C++. What did I do wrong?
[英]Switching from C# to C++. What's wrong with my code? do I NEED headers for what I'm trying to do? Class definitions within one file issue
我已经用C#编程了几年,因为这是我的第一语言。 我正在努力提高我的c ++,因为我将很快开发一些编码的东西。
这段代码出了什么问题:(我知道可能存在很多错误.C ++与C#的不同之处在于它所需要的)。 有人告诉我,我不知道如何在C ++中正确声明类,并且我需要使用头来定义我的类。 我需要标题吗? 这是一个小程序,只是为了测试,想知道是否可以在没有它的情况下完成。 丢失的标题是唯一的问题吗? 我有一个关于无法在公司中访问Parse的错误,但是当我在公司类名称前添加public时,会引发更多错误。
AUGH! 太令人沮丧了。
#include "std_lib_facilities.h"
using namespace std;
class Employee
{
public:
string screen_name;
string real_name;
string current_job;
int employee_number;
Employee(int no, string name1, string name2, string current_jobin)
{
screen_name=name1;
real_name=name2;
employee_number=no;
current_job=current_jobin;
}
};
class Project
{
public:
Vector<Employee> Employees;
int max_worker_quota;
int project_id;
string project_name;
Project(int no_in,int max_in,string title_in)
{
max_worker_quota=max_in;
project_name=title_in;
project_id=no_in;
}
};
unsigned int split(const std::string &txt, vector<std::string> &strs, char ch)
{
unsigned int pos = txt.find( ch );
unsigned int initialPos = 0;
strs.clear();
// Decompose statement
while( pos != std::string::npos ) {
strs.push_back( txt.substr( initialPos, pos - initialPos + 1 ) );
initialPos = pos + 1;
pos = txt.find( ch, initialPos );
}
// Add the last one
strs.push_back( txt.substr( initialPos, std::min( pos, txt.size() ) - initialPos + 1));
return strs.size();
}
class Company
{
Vector<Employee> Employeelist;
Vector<Project> Projectlist;
void Parse(string input)
{
//Case Statements
vector<string> temp;
split( input, temp, ' ' );
if (temp[0]=="S")
{
//Add Employee to Company
Employee myEmployee=Employee(atoi(temp[1].c_str()),temp[2],temp[3],temp[4]);
Employeelist.push_back(myEmployee);
}
else if (temp[0]=="C")
{
//Add Project to Company
Project myProject=Project(atoi(temp[1].c_str()),atoi(temp[2].c_str()),temp[3]);
Projectlist.push_back(myProject);
}
else if (temp[0]=="L")
{
//Add Employee to Project list
//Not Implemented-Find Project by temp[1] which is a int
}
else if (temp[0]=="A")
{
}
else if (temp[0]=="D")
{
}
else if (temp[0]=="PS")
{
}
else if (temp[0]=="PC")
{
}
}
};
int main(int argc, char *argv[])
{
string input;
cout<<"Command:: ";
cin>>input;
Company myCompany;
myCompany.Parse(input); //Input is in the format X Name Name etc etc. Arguments separated by spaces
return 0;
}
首先,您不需要标题用于测试目的。 但是如果没有它们,你就无法创建一个真正的程序,因为标题定义了单独编译的程序部分的接口。 这就是C / C ++的工作方式,没有办法解决。
其次,您必须将public:
添加到您的Company
类并处理以下错误。 它就像C#的东西:你必须使一个函数定义为public void Parse(string)
才能从类外部访问它。 C ++方式是
class Foo {
public:
void Bar();
};
第三,在C ++中定义类定义中的非平凡函数是非常规的(唯一的例外是模板类)。 那是标题故事的另一面。
好的,这里是基本标题相关内容的简要说明。
程序通常分为单独编译的文件集,即翻译单元。 每个单元通常由一个.cpp
文件和一个或多个头文件( .h
)组成。 编译这些文件时,您将获得一个二进制.obj文件。 该文件包含对象 - 函数代码和初始化全局(和命名空间)对象所需的东西。 要创建程序,您需要将一个或多个目标文件传递给链接器。 在VS中它发生在幕后。 您只需将.cpp文件添加到项目树中,IDE将相应地配置项目依赖项。
这就是你的代码的样子:
//File: employee.h
#ifndef EMPLOYEE_HDR /* include guard */
#define EMPLOYEE_HDR
#include <string>
using std::string;
class Employee {
public:
Employee (int no, string name1, string name2, string current_jobin);
void PayBonus(int amount);
void Fire(string reason);
int GetSalary() const
{ return m_Salary; }
/*...*/
protected:
int m_Salary;
string m_FirstName;
/* ... */
};
#endif
//File: employee.cpp
#include "employee.h"
Employee::Employee (int no, string name1, string name2, string current_jobin)
{
//definition
}
void Employee::PayBonus(int amount)
{
//definition
}
void Employee::Fire(string reason)
{
//definition
}
/* define other non-trivial class functions here */
//File: company.h
#ifndef COMPANY_HDR /* include guard */
#define COMPANY_HDR
#include <vector>
using std::vector;
#include "employee.h"
class Company {
public:
Company();
void Hire(string name);
void WorldCreditCrunch() //life is unfair
{ FireEveryone(); }
void Xmas(); //pays $5 bonus to everyone
/* ... */
protected:
vector<Employee> m_Staff;
void FireEveryone();
/* ... */
};
#endif
//File: company.cpp
#include "company.h"
Company::Company()
{
//definition
}
void Company::Hire(string name)
{
//calculate new employee ID etc
m_Staff.push_back(Employe( /*...*/));
}
void Company::FireEveryone()
{
for(size_t i = 0; i < m_Staff.size(); ++i)
m_Staff[i].Fire();
}
void Company::Xmas()
{
for(size_t i = 0; i < m_Staff.size(); ++i)
m_Staff[i].PayBonus(5);
}
/* ... */
//File: main.cpp
#include "company.h"
int main()
{
Company c;
c.Hire("John Smith");
/* ...*/
return 0;
}
所以,基本上我们会有员工 , 公司和主要单位。 employee.h
中Employee类的定义包含非平凡函数声明。 像GetSalary()
这样的简单函数就在类中定义。 它给出了编译器内联它的提示。 employee.cpp
包含其余的函数定义;
company.h
文件有#include "employee.h"
预处理器语句。 因此,我们可以在类定义及其实现文件( company.cpp
)中使用Employee对象。
main.cpp
包含程序入口点。 它可以使用Company类,因为它包含“company.h”。
如果我们在Employee :: Hire()函数实现中更改了某些内容,则只会重新编译employee.obj
。 这是此类计划组织的主要目的。 但是,如果我们更改Employee接口( employee.h
类定义),则每个程序单元都需要重新编译。
如果您执行以下操作,则需要包含防护:
#include "employee.h"
#include "company.h" /* will contain the 2nd inclusion of employee.h which will be
prevented by include guard */
基于Microsoft Visual C ++的项目通常使用#pragma once
用于相同目的。 它更容易使用,但通常不便携。
例如,如果在employee.h
中放置Employee :: Hire定义,编译器会将函数代码放在employee.obj和company.obj中(因为company.h
包含employee.h
)。 当您尝试在这种情况下链接时,链接器将遇到相同功能代码的2个版本,并将给出错误。 内联函数不会编译到单独的实体中,因此不会导致此类错误。 模板代码也是如此,它仅在模板实例化时生成。 因此,几个翻译单元可能具有相同的非内联模板功能的代码。
程序员可以定义程序的部件边界。 如果需要,您可以将公司和员工放入单个翻译单元。 VS向导倾向于为每个主要类别制作一个.h / .cpp对。 尝试制作一个MFC项目并亲自看看。
这些是基础知识。 正如我在上面的评论中所提到的,你可以从Stroustrup的“The C ++编程语言”中全面了解这些内容。
您使用public
来开始类中的一部分公共方法,而不是类本身。 也就是说,您应该在Company
类中的Parse
方法之前添加public:
.
class Company
{
Vector<Employee> Employeelist;
Vector<Project> Projectlist;
public:
void Parse(string input)
{
这只是为了扩展帕维尔自你评论中提出要求以来的第三点。
他的意思基本上是这样的:在任何真正的C ++项目中,你都希望将类的定义从它的实现中分离出来,分成两个文件:头文件( *.h
)和实现文件( *.cpp
)。 使用上面的示例,它可以像这样分开:
// Employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
#include <string>
class Employee
{
public:
Employee(int no,
std::string name1,
std::string name2,
std::string current_jobin);
private:
std::string screen_name;
std::string real_name;
std::string current_job;
int employee_number;
};
#endif
// Employee.cpp
#include "Employee.h"
Employee::Employee(int no,
std::string name1,
std::string name2,
std::string current_jobin)
{
screen_name = name1;
real_name = name2;
employee_number = no;
current_job = current_jobin;
}
// Company.h
#ifndef COMPANY_H
#define COMPANY_H
#include <vector>
#include <string>
#include "Employee.h"
#include "Project.h"
class Company
{
public:
void Parse(std::string input);
private:
std::vector<Employee> Employeelist;
std::vector<Project> Projectlist;
};
#endif
// Company.cpp
#include "Company.h"
void Company::Parse(std::string input)
{
// your code for Parse in Company goes here
}
你的main.cpp将使用上面这样的:
// main.cpp
#include <iostream>
#include <string>
#include "Company.h"
int main(int argc, char *argv[])
{
std::string input;
std::cout << "Command:: ";
std::cin >> input;
Company myCompany;
//Input is in the format X Name Name etc etc. Arguments separated by spaces
myCompany.Parse(input);
}
现在来自C#背景你可能想知道为什么事情就这样完成 - 毕竟你最终得到了两倍的文件! 简短的回答是因为C这样做了,C ++从C继承了很多包袱。
更长的答案是因为C ++不使用像C#和Java那样的“模块”系统。 构建源文件时,编译器除了要编译的当前文件外,不会查看其他任何位置。 因此,编译器知道您正在使用的类,函数或变量是否存在的唯一方法是,如果它在使用前编译的源文件中出现。 包含#include
指令引入的所有头文件和源.cpp的主体是所谓的“编译单元” - 它是一个独立的单元,包含编译器成功编译所需要知道的所有内容寻找别的地方。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.