/ home / Programming / Style /

Classes

Classes are central to developing everything as an API; a style that maximizes readability.

How does it maximize readability? §
  1. #ifndef QOAUTH2_H
  2. #define QOAUTH2_H
  3. #include <QObject>
  4. class QOAuth2 : public QObject
  5. {
  6. Q_OBJECT
  7. public:
  8. explicit QOAuth2( QObject *parent = nullptr );
  9. ~QOAuth2();
  10. QString getToken( const QString &urlForToken
  11. = "https://www.googleapis.com/oauth2/v4/token" );
  12. /* Oauth2 */
  13. QString access_token ();
  14. QString client_id ();
  15. QString client_secret ();
  16. QString code ();
  17. QString error ();
  18. QString error_description();
  19. QString error_uri ();
  20. QString expires_in ();
  21. QString grant_type ();
  22. QString password ();
  23. QString redirect_uri ();
  24. QString refresh_token ();
  25. QString response_type ();
  26. QString scope ();
  27. QString state ();
  28. QString token_type ();
  29. QString username ();
  30. void setAccess_token ( const QString &access_token );
  31. void setClient_id ( const QString &client_id );
  32. void setClient_secret ( const QString &client_secret );
  33. void setCode ( const QString &code );
  34. void setError ( const QString &error );
  35. void setError_description ( const QString &error_description );
  36. void setError_uri ( const QString &error_uri );
  37. void setExpires_in ( const QString &expires_in );
  38. void setGrant_type ( const QString &grant_type );
  39. void setPassword ( const QString &password );
  40. void setRedirect_uri ( const QString &redirect_uri );
  41. void setRefresh_token ( const QString &refresh_token );
  42. void setResponse_type ( const QString &response_type );
  43. void setScope ( const QString &scope );
  44. void setState ( const QString &state );
  45. void setToken_type ( const QString &token_type );
  46. void setUsername ( const QString &username );
  47. signals:
  48. void access_tokenChanged ();
  49. void client_idChanged ();
  50. void client_secretChanged ();
  51. void codeChanged ();
  52. void errorChanged ();
  53. void error_descriptionChanged();
  54. void error_uriChanged ();
  55. void expires_inChanged ();
  56. void grant_typeChanged ();
  57. void passwordChanged ();
  58. void redirect_uriChanged ();
  59. void refresh_tokenChanged ();
  60. void response_typeChanged ();
  61. void scopeChanged ();
  62. void stateChanged ();
  63. void token_typeChanged ();
  64. void usernameChanged ();
  65. private:
  66. QString m_Access_token ;
  67. QString m_Client_id ;
  68. QString m_Client_secret ;
  69. QString m_Code ;
  70. QString m_Error ;
  71. QString m_Error_description;
  72. QString m_Error_uri ;
  73. QString m_Expires_in ;
  74. QString m_Grant_type ;
  75. QString m_Password ;
  76. QString m_Redirect_uri ;
  77. QString m_Refresh_token ;
  78. QString m_Response_type ;
  79. QString m_Scope ;
  80. QString m_State ;
  81. QString m_Token_type ;
  82. QString m_Username ;
  83. };
  84. #endif // QOAUTH2_H
How to read a class? §
  1. Infer purpose from name.
  2. Check if subclassing QObject
  3. Note getters and setters.
  4. Note regular functions.
  5. Note signals [Applies to QObjects].
How was the above class read? §
  1. Name inferred OAuth2.
  2. Subclasses QObject.
  3. public getters and setters for all members.
  4. One regular function: QOAuth2::getToken.
  5. All signals are for setters. No special signals otherwise.
Therefore? §
  1. Understanding OAuth2 is a pre-requisite.
  2. Treat as an API. Consider subclassing.
  3. Create an instance and monitor changes.
  4. Try running QOAuth2::getToken.
  5. See what happens.
If that does not work? §
Anything else? §

How should one design a class? §
What does an API contain at minimum? §
What does QObject do for an API? §
  1. /* A class designed as an API */
  2. class Sneed : public QObject
  3. {
  4. Q_OBJECT
  5. public:
  6. int feed();
  7. signals:
  8. void feedChanged();
  9. private:
  10. int m_Feed;
  11. };
  12. /* Interfacing with that class's API */
  13. int main()
  14. {
  15. Sneed sneed;
  16. QObject::connect( &sneed, &Sneed::feedChanged, [&sneed](){
  17. // whenever m_Feed changes
  18. // this code will execute:
  19. qDebug() << sneed.feed();
  20. }
  21. }
When do you make an exception with QObject? §

Copyable and Non-copyable objects

A copyable object in real life: §
A copyable object in programming: §
A NON-copyable object in real life: §
A NON-copyable object in programming: §
Should one still develop non-copyable classes as APIs? §

Encapsulization Rules

public: §
  1. /* Bad */
  2. class Sneed
  3. {
  4. public:
  5. Feed m_Feed;
  6. Seed *m_Seed;
  7. static const inline Chuck s_Chuck{1};
  8. };
  9. /* Good */
  10. class Sneed
  11. {
  12. public:
  13. Feed feed() const;
  14. Seed *seed() const;
  15. void setFeed( const Feed &feed );
  16. void setSeed( Seed *seed );
  17. // Acceptable
  18. static const inline Chuck s_Chuck{1};
  19. private:
  20. Feed m_Feed;
  21. Seed *m_Seed{nullptr};
  22. };
Why use getter functions? §
What would I modify it for? §

protected: §
Why not in private:? §
  1. /* Bad */
  2. class Sneed
  3. {
  4. private:
  5. void clear();
  6. void reset();
  7. void update();
  8. void initiate();
  9. };
  10. /* Good */
  11. class Sneed
  12. {
  13. protected:
  14. void clear();
  15. void reset();
  16. void update();
  17. private:
  18. void initiate();
  19. };

private: §
What about custom prefixes? §
  1. /* Bad */
  2. int fancy;
  3. class Sneed
  4. {
  5. public:
  6. Sneed() {
  7. Q_ASSERT( m_query.contains( QRegularExpression("(!i)(feed|seed)") ) );
  8. QTextStream(stdout) << 9001;
  9. }
  10. private:
  11. QDir m_seed;
  12. QFile *pHobo; // p is hungarian notation for pointer
  13. QString feed;
  14. QProcess m_Rsync;
  15. static int m_Chuck;
  16. QDatabase store;
  17. QString m_Query;
  18. };
  19. /* Good */
  20. int g_Fancy;
  21. class Sneed
  22. {
  23. public:
  24. Sneed()
  25. {
  26. Q_ASSERT( m_query.contains( re_FeedOrSeed ) );
  27. QTextStream(stdout) << mn_PowerLevel;
  28. }
  29. private:
  30. QDir d_Seed ; // d is for Directory
  31. QFile *f_Hobo ; // f is for File
  32. QString m_Feed ; // m is for Member
  33. QProcess p_rsync; // p is for Process
  34. static int s_Chuck; // s is for Static
  35. QDatabase db_Store; // db is for Database
  36. QString j_Query; // j is an informal custom prefix for Javascript
  37. QString m_Query; // Prefer m if it's context appears once
  38. static inline const int mn_PowerLevel{9001};
  39. static inline const QRegularExpression re_FeedOrSeed{"(!i)(feed|seed)"};
  40. };
What are the points of these prefixes? §
  1. /* Bad */
  2. Sneed::Sneed()
  3. {
  4. QDir dir("/proc/");
  5. QFile file1( dir.absoluteFilePath("feed.txt") );
  6. QFile file2( dir.absoluteFilePath("seed.txt") );
  7. int m_Number = 911; // m_ here is heresy
  8. for ( int i = 0; i < --m_Number; i++ ) {
  9. QString str = QString::number(i);
  10. QProcess ps;
  11. ps.start( "ps", QStringList() << str );
  12. ps.waitForFinished();
  13. if ( file1.open( QIODevice::ReadOnly )
  14. && file2.open( QIODevice::WriteOnly ) ) {
  15. file2.write( file1.readAll() + ps.readAll() );
  16. }
  17. file1.close();
  18. file2.close();
  19. }
  20. qDebug() << m_Number;
  21. }
  22. /* Good */
  23. Sneed::Sneed()
  24. {
  25. QDir d("/proc/");
  26. QFile f_Feed( d.absoluteFilePath("feed.txt") );
  27. QFile f_Seed( d.absoluteFilePath("seed.txt") );
  28. int n = 911;
  29. for ( int i = 0; i < --n; i++ ) {
  30. QString s = QString::number(i);
  31. QProcess p;
  32. p.start( "ps", QStringList() << s );
  33. p.waitForFinished();
  34. if ( f_Feed.open( QIODevice::ReadOnly )
  35. && f_Seed.open( QIODevice::WriteOnly ) ) {
  36. f_Seed.write( f_Feed.readAll() + p.readAll() );
  37. }
  38. f_Feed.close();
  39. f_Seed.close();
  40. }
  41. qDebug() << n;
  42. }

(public|protected|private) slots: §
  1. /* Good */
  2. class Sneed : public QObject
  3. {
  4. Q_OBJECT
  5. signals:
  6. void feedChanged();
  7. void finished( bool success );
  8. protected slots:
  9. void onFeedchanged();
  10. void onFinished( bool success );
  11. };

signals: §
  1. /* Good */
  2. class Sneed : public QObject
  3. {
  4. Q_OBJECT
  5. public:
  6. void setFeed( QString s );
  7. void setSeed( QString s );
  8. signals:
  9. void feedChanged();
  10. void seedChanged();
  11. void started ();
  12. void paused ();
  13. void finished();
  14. void opened ();
  15. void closed ();
  16. void ready ();
  17. void errorOccured();
  18. };

Keywords and Qualifiers

explicit §
friend §
auto §
class struct union [Nested Classes] §
  1. /* Good */
  2. class Sneed
  3. {
  4. public:
  5. QString output();
  6. private:
  7. struct Container
  8. {
  9. QTime time ;
  10. QString output;
  11. QThread *thread;
  12. }
  13. QList<Container> m_ContainerList;
  14. QTime m_Time;
  15. }
const §
  1. /* Bad */
  2. Feed const *m_Feed;
  3. /* Good */
  4. const Feed *m_Feed;
enum §
  1. /* Bad */
  2. class Convenience : public QObject
  3. {
  4. Q_OBJECT
  5. public:
  6. enum Store {
  7. none = 0x0,
  8. sneed = 0x1,
  9. feed = 0x2,
  10. seed = 0x4,
  11. chuck = 0x8,
  12. hobo = 0x10,
  13. };
  14. Q_ENUM(Store)
  15. static const inline QMetaEnum s_MetaStore{ QMetaEnum::fromType<Store>() };
  16. Convenience( Store store )
  17. {
  18. switch(store) {
  19. case none: qDebug() << "none"; break;
  20. case sneed: qDebug() << "sneed"; break;
  21. case feed: qDebug() << "feed"; break;
  22. case seed: qDebug() << "seed"; break;
  23. case chuck: qDebug() << "chuck"; break;
  24. case hobo: qDebug() << "hobo"; break;
  25. default: return;
  26. }
  27. }
  28. };
  29. /* Good */
  30. class Convenience : public QObject
  31. {
  32. Q_OBJECT
  33. public:
  34. enum Store
  35. {
  36. None = 0,
  37. Sneed = 1 << 0 ,
  38. Feed = 1 << 1 ,
  39. Seed = 1 << 2 ,
  40. Chuck = 1 << 3 ,
  41. Hobo = 1 << 4 ,
  42. }; Q_ENUM(Store)
  43. static const inline QMetaEnum s_MetaStore{ QMetaEnum::fromType<Store>() };
  44. Convenience( Store store )
  45. {
  46. qDebug() << s_MetaStore.valueToKey(store);
  47. }
  48. };
inline §
  1. class Sneed
  2. {
  3. /* Bad */
  4. static bool s_Hobo;
  5. /* Good */
  6. static const bool s_Seed{true};
  7. static inline bool s_Feed{true};
  8. };
unsigned §
  1. if ( this->trySneed(60) ) { ... } // wait one minute
  2. if ( this->trySneed(-1) ) { ... } // wait forever
  3. if ( this->trySneed( 0) ) { ... } // Do not wait at all
long short signed §
  1. class Sneed
  2. {
  3. /* Bad */
  4. unsigned char m_uchar;
  5. signed char m_char;
  6. short m_16 ;
  7. long long int m_64 ;
  8. unsigned char m_u8 ;
  9. unsigned short m_u16;
  10. unsigned int m_u32;
  11. unsigned long m_u64;
  12. float m_float ;
  13. double m_double;
  14. /* fine */
  15. int m_int;
  16. /* Good */
  17. uchar m_uchar;
  18. qint8 m_char ;
  19. qint8 m_8 ;
  20. qint16 m_16 ;
  21. qint32 m_32 ;
  22. qint64 m_64 ;
  23. quint8 m_u8 ;
  24. quint16 m_u16 ;
  25. quint32 m_u32 ;
  26. quint64 m_u64 ;
  27. qreal m_real;
  28. };
operator §
register §
static §
template §
  1. /* Good */
  2. template<typename T_Enum, typename T_Key, typename T_Value>
  3. class QDatabase
  4. {
  5. public:
  6. explicit QDatabase( const QString &applicationName, const SQL_Metadata options = SQL_Metadata(0) )
  7. : m_ApplicationName( applicationName )
  8. , d_Database( QDir::home().absoluteFilePath( ".local/share/qdatabase/" + applicationName ) )
  9. , m_FileName( d_Database.absoluteFilePath(
  10. this->demangle( typeid(T_Key ).name() )
  11. + QString(".")
  12. + this->demangle( typeid(T_Value).name() )
  13. + mn_Mime ) )
  14. , m_Metadata( options )
  15. {
  16. Q_ASSERT( QSqlDatabase::isDriverAvailable( mn_Driver ) );
  17. Q_ASSERT( s_MetaEnum.keyCount() != 0 );
  18. this->init();
  19. for ( int i = 0; i < s_MetaEnum.keyCount(); i++ ) {
  20. m_ColumnNames.append( s_MetaEnum.key(i) );
  21. }
  22. }
  23. /* [ etc... ] */
  24. }
mutable §
virtual §
typedef|using §
  1. template<typename T>
  2. class Sneed
  3. {
  4. /* Bad */
  5. typedef QList<T> seed;
  6. typedef void (*feed)();
  7. /* Fine */
  8. typedef unsigned long long quint64;
  9. using quint64 = unsigned long long;
  10. /* Good */
  11. using seed = QList<T>;
  12. using feed = void (*)();
  13. template <typename T_Feed, typename T_Seed> using Chuck = QPair<T_Feed,T_Seed>;
  14. };
volatile §