C ++编程风格
我是一个老的(但不太老)Java程序员,他决定学习C ++。 但是我已经看到了很多C ++编程风格,好吧,只是该死的丑!
所有这些将类定义放在头文件中的方法,以及将方法放在不同的源文件中 - 调用函数无处不在,而不是在类中使用方法。 所有这些似乎......错了!
那么最后,我是否有理由继续对OOP进行这次大屠杀,以及编程中的任何好的和正义的事情,还是我可以忽略那些老式的C ++约定,并使用我的良好Java编程风格?
顺便说一句,我正在学习C ++,因为我想做游戏编程。
这里是一个例子:
在C ++网站中,我找到了一个Windows实现:
class WinClass
{
public:
WinClass (WNDPROC wndProc, char const * className, HINSTANCE hInst);
void Register ()
{
::RegisterClass (&_class);
}
private:
WNDCLASS _class;
};
该类位于头文件和构造函数中:
WinClass::WinClass (WNDPROC wndProc, char const * className, HINSTANCE hInst)
{
_class.style = 0;
_class.lpfnWndProc = wndProc; // Window Procedure: mandatory
_class.cbClsExtra = 0;
_class.cbWndExtra = 0;
_class.hInstance = hInst; // Owner of the class: mandatory
_class.hIcon = 0;
_class.hCursor = ::LoadCursor (0, IDC_ARROW); // Optional
_class.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // Optional
_class.lpszMenuName = 0;
_class.lpszClassName = className; // Mandatory
}
位于.cpp源文件。
我可以做的是:
class WinClass
{
public:
WinClass (WNDPROC wndProc, char const * className, HINSTANCE hInst)
{
_class.style = 0;
_class.lpfnWndProc = wndProc; // Window Procedure: mandatory
_class.cbClsExtra = 0;
_class.cbWndExtra = 0;
_class.hInstance = hInst; // Owner of the class: mandatory
_class.hIcon = 0;
_class.hCursor = ::LoadCursor (0, IDC_ARROW); // Optional
_class.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // Optional
_class.lpszMenuName = 0;
_class.lpszClassName = className; // Mandatory
}
void Register ()
{
::RegisterClass (&_class);
}
private:
WNDCLASS _class;
};
现在构造函数在它的类中。
除了其他人在这里所说的话之外,还有更重要的问题:
1)大型翻译单元导致更长的编译时间和更大的目标文件大小。
2)循环依赖! 这是最大的一个。 它几乎总是可以通过拆分标题和源代码来解决:
// Vehicle.h
class Wheel {
private:
Car& m_parent;
public:
Wheel( Car& p ) : m_parent( p ) {
std::cout << "Car has " << m_parent.numWheels() << " wheels." << std::endl;
}
};
class Car {
private:
std::vector< Wheel > m_wheels;
public:
Car() {
for( int i=0; i<4; ++i )
m_wheels.push_back( Wheel( *this ) );
}
int numWheels() {
return m_wheels.size();
}
}
不管你把这些命令放在什么位置,人们总是会缺乏另一个的定义,即使使用前向声明也不行,因为函数体中正在使用关于每个类的符号的细节。
但是,如果将它们分解为适当的.h和.cpp文件并使用前向声明,它将满足编译器的要求:
//Wheel.h
//-------
class Car;
class Wheel {
private:
Car& m_parent;
public:
Wheel( Car& p );
};
//Wheel.cpp
//---------
#include "Wheel.h"
#include "Car.h"
Wheel::Wheel( Car& p ) : m_parent( p ) {
std::cout << "Car has " << m_parent.numWheels() << " wheels." << std::endl;
}
//Car.h
//-----
class Wheel;
class Car {
private:
std::vector< Wheel > m_wheels;
public:
Car();
int numWheels();
}
//Car.cpp
//-------
#include "Car.h"
#include "Wheel.h"
Car::Car() {
for( int i=0; i<4; ++i )
m_wheels.push_back( Wheel( *this ) );
}
int Car::numWheels() {
return m_wheels.size();
}
现在,实际上必须知道关于第二类的细节的代码可以包含头文件,该文件不需要知道关于第一类的细节。
当源文件提供定义时,标题只提供声明。 或者说另一种说法:标题告诉你什么是(有效的符号可用)和源代码告诉编译器这些符号实际上做了什么。 在C ++中,除了有效的符号外,不需要任何东西就可以开始使用它。
相信C ++有这个习惯用法的一个原因,因为如果你不这样做,你会为自己的生产线造成很多麻烦。 我知道 :/
在构建代码时,C ++预处理器会构建一个翻译单元。 它以.cpp文件开头,解析#includes从头文件中获取文本,并生成一个包含所有头文件和.cpp代码的大文本文件。 然后,这个翻译单元被编译成将在您定位的平台上运行的代码。 每个翻译单元最终成为一个目标文件。
因此,.h文件包含在多个翻译单元中,并且.cpp文件仅包含在一个中。
如果.h文件包含很多东西(包括实现),那么翻译单元会相应地变大。 编译时间会增加,并且当您更改标题中的任何内容时......每个使用它的翻译单元都需要重新编译。
所以..最小化.h文件中的东西大大提高了编译时间。 您可以编辑.cpp文件来更改函数,并且只需要重建一个翻译单元。
为了完成关于编译的故事......
一旦所有的翻译单元都被构建成目标文件(本地平台的本地二进制代码)。 链接器完成它的工作,并将它们拼接到你的.exe,.dll或.lib文件中。 .lib文件可以链接到另一个版本,因此可以在多个.exe或.dll中重复使用.lib文件。
我认为Java编译模型更加先进,并且放置代码的位置意义不大。
.h和.cpp文件通常将声明和定义分开,这里有一些顺序和概念封装。 头文件有'什么',实现文件有'如何'。
我发现在java中的一个文件中的一切都是混乱的。 所以,每一个都是属于自己的。
就像任何其他语言对其社区习惯用法一样,C ++惯例和惯用语都经过深思熟虑的推理。
我认为最好是在你编写Java时使用java(作为动词),当使用C ++时使用C ++! 你会明白为什么有语言的经验。 与切换到任何新语言相同。
链接地址: http://www.djcxy.com/p/85407.html