从C#转向C++,有好的参考资料吗?

4
我刚刚完成了我的第二个面向对象编程课程,我的第一和第二个课程都是用C#教授的,但是在接下来的编程课程中,我们将使用C++。具体而言,我们将使用Visual C++编译器。问题是,我们需要自己学习C++的基础知识,没有老师进行过渡。因此,我想知道你们是否知道一些好的资源可以让我从C#背景中学习C++?
我之所以问这个问题,是因为我注意到C#和C++之间存在许多差异,例如声明您的main方法int并返回0,以及您的main方法并不总是包含在一个类中。另外,我注意到所有的类都必须在main方法之前编写,我听说这是因为VC++从上往下编译。
无论如何,你知道一些好的参考资料吗?
谢谢!(还有,是否有某个地方可以比较我在C#中编写的简单程序,在C++中会是什么样子,例如我写的下面的程序?)
using System;
using System.IO;
using System.Text; // for stringbuilder

class Driver
{
const int ARRAY_SIZE = 10;

static void Main()
{
    PrintStudentHeader(); // displays my student information header

    Console.WriteLine("FluffShuffle Electronics Payroll Calculator\n");
    Console.WriteLine("Please enter the path to the file, either relative to your current location, or the whole file path\n");

    int i = 0;

    Console.Write("Please enter the path to the file: ");
    string filePath = Console.ReadLine();

    StreamReader employeeDataReader = new StreamReader(filePath);

    Employee[] employeeInfo = new Employee[ARRAY_SIZE];

    Employee worker;

    while ((worker = Employee.ReadFromFile(employeeDataReader)) != null)
    {
        employeeInfo[i] = worker;
        i++;
    }

    for (int j = 0; j < i; j++)
    {
        employeeInfo[j].Print(j);
    }

    Console.ReadLine();

}//End Main()


class Employee
{
const int TIME_AND_A_HALF_MARKER = 40;
const double FEDERAL_INCOME_TAX_PERCENTAGE = .20;
const double STATE_INCOME_TAX_PERCENTAGE = .075;
const double TIME_AND_A_HALF_PREMIUM = 0.5;

private int employeeNumber;
private string employeeName;
private string employeeStreetAddress;
private double employeeHourlyWage;
private int employeeHoursWorked;
private double federalTaxDeduction;
private double stateTaxDeduction;
private double grossPay;
private double netPay;

// -------------- Constructors ----------------

public Employee() : this(0, "", "", 0.0, 0) { }

public Employee(int a, string b, string c, double d, int e)
{
    employeeNumber = a;
    employeeName = b;
    employeeStreetAddress = c;
    employeeHourlyWage = d;
    employeeHoursWorked = e;
    grossPay = employeeHourlyWage * employeeHoursWorked;

    if (employeeHoursWorked > TIME_AND_A_HALF_MARKER)
        grossPay += (((employeeHoursWorked - TIME_AND_A_HALF_MARKER) * employeeHourlyWage) * TIME_AND_A_HALF_PREMIUM);

    stateTaxDeduction = grossPay * STATE_INCOME_TAX_PERCENTAGE;
    federalTaxDeduction = grossPay * FEDERAL_INCOME_TAX_PERCENTAGE;
}

// --------------- Setters -----------------

/// <summary>
/// The SetEmployeeNumber method
/// sets the employee number to the given integer param
/// </summary>
/// <param name="n">an integer</param>
public void SetEmployeeNumber(int n)
{
    employeeNumber = n;
}

/// <summary>
/// The SetEmployeeName method
/// sets the employee name to the given string param
/// </summary>
/// <param name="s">a string</param>
public void SetEmployeeName(string s)
{
    employeeName = s;
}

/// <summary>
/// The SetEmployeeStreetAddress method
/// sets the employee street address to the given param string
/// </summary>
/// <param name="s">a string</param>
public void SetEmployeeStreetAddress(string s)
{
    employeeStreetAddress = s;
}

/// <summary>
/// The SetEmployeeHourlyWage method
/// sets the employee hourly wage to the given double param
/// </summary>
/// <param name="d">a double value</param>
public void SetEmployeeHourlyWage(double d)
{
    employeeHourlyWage = d;
}

/// <summary>
/// The SetEmployeeHoursWorked method
/// sets the employee hours worked to a given int param
/// </summary>
/// <param name="n">an integer</param>
public void SetEmployeeHoursWorked(int n)
{
    employeeHoursWorked = n;
}

// -------------- Getters --------------

/// <summary>
/// The GetEmployeeNumber method
/// gets the employee number of the currnt employee object
/// </summary>
/// <returns>the int value, employeeNumber</returns>
public int GetEmployeeNumber()
{
    return employeeNumber;
}

/// <summary>
/// The GetEmployeeName method
/// gets the name of the current employee object
/// </summary>
/// <returns>the string, employeeName</returns>
public string GetEmployeeName()
{
    return employeeName;
}

/// <summary>
/// The GetEmployeeStreetAddress method
/// gets the street address of the current employee object
/// </summary>
/// <returns>employeeStreetAddress, a string</returns>
public string GetEmployeeStreetAddress()
{
    return employeeStreetAddress;
}

/// <summary>
/// The GetEmployeeHourlyWage method
/// gets the value of the hourly wage for the current employee object
/// </summary>
/// <returns>employeeHourlyWage, a double</returns>
public double GetEmployeeHourlyWage()
{
    return employeeHourlyWage;
}

/// <summary>
/// The GetEmployeeHoursWorked method
/// gets the hours worked for the week of the current employee object
/// </summary>
/// <returns>employeeHoursWorked, as an int</returns>
public int GetEmployeeHoursWorked()
{
    return employeeHoursWorked;
}

// End --- Getter/Setter methods

/// <summary>
/// The CalcSalary method
/// calculates the net pay of the current employee object
/// </summary>
/// <returns>netPay, a double</returns>
private double CalcSalary()
{
    netPay = grossPay - stateTaxDeduction - federalTaxDeduction;

    return netPay;
}

/// <summary>
/// The ReadFromFile method
/// reads in the data from a file using a given a streamreader object
/// </summary>
/// <param name="r">a streamreader object</param>
/// <returns>an Employee object</returns>
public static Employee ReadFromFile(StreamReader r)
{
    string line = r.ReadLine();

    if (line == null)
        return null;

    int empNumber = int.Parse(line);
    string empName = r.ReadLine();
    string empAddress = r.ReadLine();
    string[] splitWageHour = r.ReadLine().Split();
    double empWage = double.Parse(splitWageHour[0]);
    int empHours = int.Parse(splitWageHour[1]);

    return new Employee(empNumber, empName, empAddress, empWage, empHours);
}

/// <summary>
/// The Print method
/// prints out all of the information for the current employee object, uses string formatting
/// </summary>
/// <param name="checkNum">The number of the FluffShuffle check</param>
public void Print(int checkNum)
{
    string formatStr = "| {0,-45}|";

    Console.WriteLine("\n\n+----------------------------------------------+");
    Console.WriteLine(formatStr, "FluffShuffle Electronics");
    Console.WriteLine(formatStr, string.Format("Check Number: 231{0}", checkNum));
    Console.WriteLine(formatStr, string.Format("Pay To The Order Of:  {0}", employeeName));
    Console.WriteLine(formatStr, employeeStreetAddress);
    Console.WriteLine(formatStr, string.Format("In The Amount of {0:c2}", CalcSalary()));
    Console.WriteLine("+----------------------------------------------+");
    Console.Write(this.ToString());
    Console.WriteLine("+----------------------------------------------+");
}

/// <summary>
/// The ToString method
/// is an override of the ToString method, it builds a string
/// using string formatting, and returns the built string. It particularly builds a string containing
/// all of the info for the pay stub of a sample employee check
/// </summary>
/// <returns>A string</returns>
public override string ToString()
{
    StringBuilder printer = new StringBuilder();

    string formatStr = "| {0,-45}|\n";

    printer.AppendFormat(formatStr,string.Format("Employee Number:  {0}", employeeNumber));
    printer.AppendFormat(formatStr,string.Format("Address:  {0}", employeeStreetAddress));
    printer.AppendFormat(formatStr,string.Format("Hours Worked:  {0}", employeeHoursWorked));
    printer.AppendFormat(formatStr,string.Format("Gross Pay:  {0:c2}", grossPay));
    printer.AppendFormat(formatStr,string.Format("Federal Tax Deduction:  {0:c2}", federalTaxDeduction));
    printer.AppendFormat(formatStr,string.Format("State Tax Deduction:  {0:c2}", stateTaxDeduction));
    printer.AppendFormat(formatStr,string.Format("Net Pay:    {0:c2}", CalcSalary()));

    return printer.ToString();

}
}
6个回答

7
C++和C#是不同的编程语言,具有不同的语义和规则。没有一种简单快捷的方法可以从一个语言切换到另一个语言。你需要学习C++。为此,了解C++的资源可能会给出一些有趣的建议。还可以搜索C++书籍-例如参考definitive C++ book guide and list。无论如何,你需要花费大量时间来学习C++。如果你的老师期望你突然就懂C++,那么你的学校存在严重问题。

1
我怀疑他们不指望他一下子就知道它。前几个任务通常足够简单,你可以在完成它们的同时学会这种语言。 - mpen

7
我的建议是:
不要从C#的角度来看待C++。从头开始学习C++,并尝试阅读一本好的、扎实的C++教材。
试图将C++映射到C#的思维方式将不能使你成为一个优秀的C++开发者——它们真的非常不同。从C#到C++进行移植非常困难(不是C++/CLI,而是纯C++),因为C#的很多内容都是.NET框架,而在C++中无法使用。
此外,在C++中有很多事情与C#的做法截然不同。虽然C#泛型看起来像C++模板,但它们非常不同,当在C++中工作时,这种变化会变得普遍。
你的经验会让很多事情变得更容易,但最好将其视为一个完全不同的语言。

1

我不知道是否有一个可以比较你的代码和C++实现的“地方”。相反,我建议你找到一位本地的面向对象开发专家,让他或她对你的示例代码进行彻底的代码审查。之后,他或她可能会与你一起讨论C++移植问题,你会发现这两种语言并没有太大的区别。(库是你会发现有意义的差异的地方,而不是语言;但在这一点上,这可能对你来说并不是一个相关的区别。)

代码审查与向教授或助教请教有所不同。教授可能没有时间与你进行全面的审查(尽管他们可能会在办公室里讨论一些要点)。一个好的代码审查人员将逐行地为您讲解代码,提供反馈和问题,例如“你认为我会或不会这样做吗?”、“你考虑过如果你的需求变成X会发生什么吗?”、“如果其他人想重用Y,这段代码会发生什么?”在审查过程中,他们将帮助您巩固良好的面向对象编程原则。从已经完成了很多这样的工作的人那里学到很多新东西。(找到一个好的人可能是困难的任务——如果可能的话,请获得推荐,或者寻求熟悉重构的人。也可以请求助教或研究生来做。)对于您上面的代码,我预计需要花费一两个小时。
您还可以考虑通过电子邮件或在评论/答案中向StackOverflow社区请求代码审查。我相信您会得到丰富多彩的答案,并且讨论很可能是有益的。

对于经验丰富的人的代码进行代码审查也是很有价值的——询问“你为什么这样做?”可以带来深入的见解;当新手在大师的代码中发现一个错误时,这总是非常有趣的。

在与专家进行了一次或两次审查后,考虑与同班同学一起进行代码审查,互相审查彼此的代码。即使是没有经验的眼睛也可能会提出一个问题,引发更深层次的理解。

我知道你需要考虑C++的课程作业,但你也需要更多地练习面向对象设计的基础知识。一旦你有了更多的实践经验,你会发现所有基于C的语言基本上都是一组共同思想的语法变体——尽管某些语言特性会让你的工作更容易,但有些则会让它变得更难。


1

许多大学在教授C++之前或者甚至是代替C++来教授C#/Java。这是因为人们认为在一门不允许使用C++中仍然可能存在的非面向对象方法的语言中学习面向对象开发会更加正确。

你应该直接问你的教授是否是这种情况。

如果是这样,你会发现他/她只会在必要的时候温和地介绍C++的具体内容。目的是让你能够将你在C#中学到的许多良好实践应用到你的C++代码中。你还将更清楚地看到C++允许你打破一些面向对象规则,甚至更重要的是,这可能是有用的。

另外,如果你发现你的教授没有给出指导就直接讲解C++指针和内存管理(正如其他人所说),那么这门课程看起来并不是很好计划。在这种情况下,你可能需要考虑获取Stroustrup的C++ Programming Language副本。


0

-1

始终记住的一件重要事情是,在C#中当你传递一个对象时,实际上你传递的是对该对象的引用。

C#: void EnrollStudent( Student s ) s是指向实际对象的引用(内存位置)。

C++: void EnrollStudent( Student s ) s是实际对象。无论对象有多大,你在堆栈中占用的空间就有多大。

C++中与C#方法等效的代码为 void EnrollStudent( Student* s )


1
我以为C++的等价写法是void EnrollStudent(Student& s)。难道没有区别吗? - Alex
@Alex,你指定的函数原型将通过引用传递Student对象。在C++中这样做可以允许函数修改参数(就像在C#中),但是你仍然会将整个对象传递给函数,而不是像void EnrollStudent(Student* s)那样传递指针。最终结果相同,但性能更好。请查看此链接:http://pages.cs.wisc.edu/~hasti/cs368/CppTutorial/NOTES/PARAMS.html - Babak Naffas
在引用和指针之间真的有性能差异吗?我认为引用在编译时被转换为指针。 - gtrak
@BabakNaffas:不,如果你通过引用传递,你并没有传递“整个对象”。传递指针和引用应该具有相同的性能,因为大多数编译器将引用参数实现为指针。 - Mooing Duck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接