There are a few things that I almost always do when I put a class together in C++.
当我在C ++中将一个类放在一起时,我几乎总是会做一些事情。
1) Virtual Destructor 2) Copy constructor and assignment operator (I either implement them in terms of a private function called Copy(), or declare them private and thus explicitly disallow the compiler to auto generate them).
1)虚拟析构函数2)复制构造函数和赋值运算符(我根据名为Copy()的私有函数实现它们,或者将它们声明为私有,从而明确禁止编译器自动生成它们)。
What things do you find are almost always useful?
你发现什么东西几乎总是有用的?
10 个解决方案
#1
10
I find turning on the gcc flags -Wall
, -Werror
, and (this is the fun one) -Weffc++
help catch a lot of potential problems. From the gcc man page:
我发现打开gcc标志-Wall,-Werror和(这很有趣)-Weffc ++帮助抓住了很多潜在的问题。从gcc手册页:
-Weffc++ (C++ only) Warn about violations of the following style guidelines from Scott Meyers’ Effective C++ book: · Item 11: Define a copy constructor and an assignment operator for classes with dynamically allocated memory. · Item 12: Prefer initialization to assignment in constructors. · Item 14: Make destructors virtual in base classes. · Item 15: Have "operator=" return a reference to *this. · Item 23: Don’t try to return a reference when you must return an object. and about violations of the following style guidelines from Scott Meyers’ More Effective C++ book: · Item 6: Distinguish between prefix and postfix forms of incre- ment and decrement operators. · Item 7: Never overload "&&", "││", or ",". If you use this option, you should be aware that the standard library headers do not obey all of these guidelines; you can use grep -v to filter out those warnings.
#2
14
Oddly, most of the suggestions here are things I specifically don't do.
奇怪的是,这里的大多数建议都是我特别不做的事情。
- I don't make dtors virtual unless I am designing it specifically to be inherited. It adds a lot of overhead and prevents automatic inlining, which is bad since most dtors are empty anyways (and few classes benefit from inheritance)
- I don't make copy ctor/assignment op unless the defaults won't work -- and if it won't, I may want to reconsider the design. Remember, between string & vector, there's hardly ever a reason to call new anymore. And creating your own copy ctor identical to the default one will almost certainly be less efficient.
- I don't add string cast. It causes too many problems where the cast is called silently where you didn't intend it to be. Better to add a ToString() method.
- I don't add a friend oper<<, because friends are evil and messy. Better to add a Display(ostream) method. Then the oper<< can call that, and doesn't need to be a friend. In fact, you could make the oper<< a template function calling Display() and never have to worry about it again.
除非我专门为继承设计它,否则我不会将dtors设为虚拟。它增加了很多开销并且阻止了自动内联,这很糟糕,因为大多数dtors都是空的(并且很少有类受益于继承)
除非默认设置不起作用,否则我不会复制ctor / assignment op,如果不能,我可能要重新考虑设计。请记住,在字符串和向量之间,几乎没有理由再打电话给新的。创建与默认版本相同的复制文件几乎肯定会降低效率。
我不添加字符串强制转换。它会引起太多问题,在这些问题中,无意中调用了强制转换。最好添加ToString()方法。
我没有添加朋友oper <<,因为朋友是邪恶和凌乱的。最好添加一个Display(ostream)方法。那么oper < <可以称之为,而不需要成为朋友。事实上,你可以使oper <<模板函数调用display(),而不必再担心它。< p>
#3
4
The first i do when putting a class together is putting some doxygen comment above it about why it exists and what it does.
我在将课程放在一起时所做的第一件事就是在它上面加上一些关于它存在的原因以及它的作用。
I once worked on a group project where they said they want to document the stuff at the end of the project. And it was all of a mess to put the comments into the code later on. I don't want to have this happen again.
我曾经在一个小组项目上工作,他们说他们想在项目结束时记录这些东西。稍后将注释放入代码中就太乱了。我不想再发生这种情况。
#4
3
Adding a semicolon after the class definition. This continuously bites me in the ass every time I forget to do it since gcc's error messages are vague and it generally says something like "can't define a type in the return type of a function" which doesn't mean a whole lot...
在类定义后添加分号。每次我忘记这样做时,这都会让我陷入困境,因为gcc的错误信息含糊不清,而且它通常会说“无法在函数的返回类型中定义类型”,这并不意味着很多。 ..
#5
3
Stop and think
停下来想一想
#6
2
Often,
operator string () const;
or
friend ostream& operator << (ostream&, const MyClass&);
#7
1
In header files, do
在头文件中,执行
#ifndef __SOMEDEFINE__
#define __SOMEDEFINE__
#endif
In VS, I add
在VS中,我补充道
#pragma warning(disable: 4786)
Oh, I also use
哦,我也用
#include <inttypes.h>
cuz I <3 C99 types.
因为我<3 C99类型。
#8
1
I usually include an enum of return codes, so the class can tell its callers what happened in its member functions. Most often, this will be the only type returned by all the members of the class. All results are passed back by reference.
我通常包含一个返回码枚举,因此该类可以告诉其调用者其成员函数中发生了什么。大多数情况下,这将是该类所有成员返回的唯一类型。所有结果均以参考方式传回。
#9
1
I start by calling the development environment macro that sets up the include guards (#ifdefs and/or #pragma once).
我首先调用设置包含保护的开发环境宏(#ifdefs和/或#pragma once)。
Next I stub out the class name and any namespace it will be in, without adding any functionality at all.
接下来,我将删除类名及其所在的任何名称空间,而不添加任何功能。
Then I create the unit test file for that class, and add the first test (usually a parameter constructor test).
然后我为该类创建单元测试文件,并添加第一个测试(通常是参数构造函数测试)。
I just work from there, writing and refactoring the class as I think about what I really need from it. Things I tend to test specifically: const-correctness, implicit and explicit conversions, types of exceptions thrown, etc.
我只是在那里工作,编写和重构课程,因为我想到了我真正需要的东西。我倾向于专门测试的东西:const-correctness,隐式和显式转换,抛出的异常类型等。
#10
1
The first thing I do with a totally new class file is to write several paragraphs of comments on what the class does, why it exists, what classes it uses and how to use it. It should be enough that someone who randomly opens up a file in a module knows enough from that comment to find the file they are actually looking for.
我用一个全新的类文件做的第一件事是写几段注释,关于类的作用,它存在的原因,它使用的类以及如何使用它。在模块中随机打开文件的人应该足够了解该注释以找到他们实际查找的文件。
I agree with James - I am very careful not to add functionality to a class that does not need it, most classes do not need a virtual destructor (or a destructor at all). If they do, I question why they don't just use smart pointers and other automatic memory management. Obviously there are many classes (i.e smart scoped locks) that DO need a destructor but it is not just a matter of course to make on.
我同意James的观点 - 我非常小心,不要将功能添加到不需要它的类中,大多数类不需要虚拟析构函数(或根本不需要析构函数)。如果他们这样做,我怀疑为什么他们不只是使用智能指针和其他自动内存管理。显然有许多类(即智能范围锁)需要一个析构函数,但它不仅仅是理所当然的。
#1
10
I find turning on the gcc flags -Wall
, -Werror
, and (this is the fun one) -Weffc++
help catch a lot of potential problems. From the gcc man page:
我发现打开gcc标志-Wall,-Werror和(这很有趣)-Weffc ++帮助抓住了很多潜在的问题。从gcc手册页:
-Weffc++ (C++ only) Warn about violations of the following style guidelines from Scott Meyers’ Effective C++ book: · Item 11: Define a copy constructor and an assignment operator for classes with dynamically allocated memory. · Item 12: Prefer initialization to assignment in constructors. · Item 14: Make destructors virtual in base classes. · Item 15: Have "operator=" return a reference to *this. · Item 23: Don’t try to return a reference when you must return an object. and about violations of the following style guidelines from Scott Meyers’ More Effective C++ book: · Item 6: Distinguish between prefix and postfix forms of incre- ment and decrement operators. · Item 7: Never overload "&&", "││", or ",". If you use this option, you should be aware that the standard library headers do not obey all of these guidelines; you can use grep -v to filter out those warnings.
#2
14
Oddly, most of the suggestions here are things I specifically don't do.
奇怪的是,这里的大多数建议都是我特别不做的事情。
- I don't make dtors virtual unless I am designing it specifically to be inherited. It adds a lot of overhead and prevents automatic inlining, which is bad since most dtors are empty anyways (and few classes benefit from inheritance)
- I don't make copy ctor/assignment op unless the defaults won't work -- and if it won't, I may want to reconsider the design. Remember, between string & vector, there's hardly ever a reason to call new anymore. And creating your own copy ctor identical to the default one will almost certainly be less efficient.
- I don't add string cast. It causes too many problems where the cast is called silently where you didn't intend it to be. Better to add a ToString() method.
- I don't add a friend oper<<, because friends are evil and messy. Better to add a Display(ostream) method. Then the oper<< can call that, and doesn't need to be a friend. In fact, you could make the oper<< a template function calling Display() and never have to worry about it again.
除非我专门为继承设计它,否则我不会将dtors设为虚拟。它增加了很多开销并且阻止了自动内联,这很糟糕,因为大多数dtors都是空的(并且很少有类受益于继承)
除非默认设置不起作用,否则我不会复制ctor / assignment op,如果不能,我可能要重新考虑设计。请记住,在字符串和向量之间,几乎没有理由再打电话给新的。创建与默认版本相同的复制文件几乎肯定会降低效率。
我不添加字符串强制转换。它会引起太多问题,在这些问题中,无意中调用了强制转换。最好添加ToString()方法。
我没有添加朋友oper <<,因为朋友是邪恶和凌乱的。最好添加一个Display(ostream)方法。那么oper < <可以称之为,而不需要成为朋友。事实上,你可以使oper <<模板函数调用display(),而不必再担心它。< p>
#3
4
The first i do when putting a class together is putting some doxygen comment above it about why it exists and what it does.
我在将课程放在一起时所做的第一件事就是在它上面加上一些关于它存在的原因以及它的作用。
I once worked on a group project where they said they want to document the stuff at the end of the project. And it was all of a mess to put the comments into the code later on. I don't want to have this happen again.
我曾经在一个小组项目上工作,他们说他们想在项目结束时记录这些东西。稍后将注释放入代码中就太乱了。我不想再发生这种情况。
#4
3
Adding a semicolon after the class definition. This continuously bites me in the ass every time I forget to do it since gcc's error messages are vague and it generally says something like "can't define a type in the return type of a function" which doesn't mean a whole lot...
在类定义后添加分号。每次我忘记这样做时,这都会让我陷入困境,因为gcc的错误信息含糊不清,而且它通常会说“无法在函数的返回类型中定义类型”,这并不意味着很多。 ..
#5
3
Stop and think
停下来想一想
#6
2
Often,
operator string () const;
or
friend ostream& operator << (ostream&, const MyClass&);
#7
1
In header files, do
在头文件中,执行
#ifndef __SOMEDEFINE__
#define __SOMEDEFINE__
#endif
In VS, I add
在VS中,我补充道
#pragma warning(disable: 4786)
Oh, I also use
哦,我也用
#include <inttypes.h>
cuz I <3 C99 types.
因为我<3 C99类型。
#8
1
I usually include an enum of return codes, so the class can tell its callers what happened in its member functions. Most often, this will be the only type returned by all the members of the class. All results are passed back by reference.
我通常包含一个返回码枚举,因此该类可以告诉其调用者其成员函数中发生了什么。大多数情况下,这将是该类所有成员返回的唯一类型。所有结果均以参考方式传回。
#9
1
I start by calling the development environment macro that sets up the include guards (#ifdefs and/or #pragma once).
我首先调用设置包含保护的开发环境宏(#ifdefs和/或#pragma once)。
Next I stub out the class name and any namespace it will be in, without adding any functionality at all.
接下来,我将删除类名及其所在的任何名称空间,而不添加任何功能。
Then I create the unit test file for that class, and add the first test (usually a parameter constructor test).
然后我为该类创建单元测试文件,并添加第一个测试(通常是参数构造函数测试)。
I just work from there, writing and refactoring the class as I think about what I really need from it. Things I tend to test specifically: const-correctness, implicit and explicit conversions, types of exceptions thrown, etc.
我只是在那里工作,编写和重构课程,因为我想到了我真正需要的东西。我倾向于专门测试的东西:const-correctness,隐式和显式转换,抛出的异常类型等。
#10
1
The first thing I do with a totally new class file is to write several paragraphs of comments on what the class does, why it exists, what classes it uses and how to use it. It should be enough that someone who randomly opens up a file in a module knows enough from that comment to find the file they are actually looking for.
我用一个全新的类文件做的第一件事是写几段注释,关于类的作用,它存在的原因,它使用的类以及如何使用它。在模块中随机打开文件的人应该足够了解该注释以找到他们实际查找的文件。
I agree with James - I am very careful not to add functionality to a class that does not need it, most classes do not need a virtual destructor (or a destructor at all). If they do, I question why they don't just use smart pointers and other automatic memory management. Obviously there are many classes (i.e smart scoped locks) that DO need a destructor but it is not just a matter of course to make on.
我同意James的观点 - 我非常小心,不要将功能添加到不需要它的类中,大多数类不需要虚拟析构函数(或根本不需要析构函数)。如果他们这样做,我怀疑为什么他们不只是使用智能指针和其他自动内存管理。显然有许多类(即智能范围锁)需要一个析构函数,但它不仅仅是理所当然的。