LIFE LOG(ここにはあなたのブログ名)

あつあつ備忘録

ソフトやハード、時にはメカの備忘録をまとめていきます

【C++】インライン関数

f:id:AtsuyaKoike:20190524095847p:plain:w300

インライン関数の特徴

  • メリット
    • 関数の呼び出しと終了時に伴うオーバーヘッドが発生しないことから、通常の関数よりも早く実行できる。
  • デメリット
    • ファイルサイズが大きくなる。
    • ループ、goto、switchを含めることができない
    • 再帰してはいけない
  • 関数定義の前にinlineと記述するだけでインライン関数となる。
  • 関数の規模が大きい時など、コンパイラが要求を実行できない場合は通常の関数としてコンパイルされる。
  • インライン関数もオーバーロードすることができる
#include <iostream>
using namespace std;

inline int even( int x ) {
    return !(x%2);
}

int main() {
    if( even(10) ) cout << "10は偶数です\n";
    if( even(11) ) cout << "11は偶数です\n";
    return 0;
}
$ g++ -o study67 study67.cpp 
$ ./study67
10は偶数です




自動インライン化

#include <iostream>

using namespace std;

class samp {
    int i, j;
public:
    samp( int a, int b ) {
        i = a;
        j = b;
    }
    int divisible() {
        return (i/j);
    }
};

int main() {
    samp sp( 20, 5 );

    cout << sp.divisible() << endl;
}
$ g++ -o study72 study72.cpp 
$ ./study72 
4
  • ただし、入出力演算子はそもそも遅いので恩恵はあまり得られない
  • 短くなるため、恩恵がない場合でもクラスの中に書くことは多い




引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】継承②

f:id:AtsuyaKoike:20190524095847p:plain:w300

study54.cpp

#include <iostream>
#include <cstring>
using namespace std;

enum yn { no, yes };
enum color { red, yellow, green, orange };
void out( enum yn x );
char *c[] = { "赤", "黄", "緑", "オレンジ" };

class fruit {
public:
    enum yn annual;
    enum yn perennial;
    enum yn tree;
    enum yn tropical;
    enum color clr;
    char name[40];
};

class Apple : public fruit {
    enum yn cooking;
    enum yn crunchy;
    enum yn eating;
public:
    void seta( char *n, enum color c, enum yn ck, enum yn crchy, enum yn e );
    void show();
};

class Orange : public fruit {
    enum yn juice;
    enum yn sour;
    enum yn eating;
public:
    void seto( char *n, enum color c, enum yn j, enum yn sr, enum yn e );
    void show();
};

void Apple::seta( char *n, enum color c, enum yn ck, enum yn crchy, enum yn e ) {
    strcpy( name, n );
    annual = no;
    perennial = yes;
    tree = yes;
    tropical = no;
    clr = c;
    cooking = ck;
    crunchy = crchy;
    eating = e;
}

void Orange::seto( char *n, enum color c, enum yn j, enum yn sr, enum yn e ) {
    strcpy( name, n );
    annual = no;
    perennial = yes;
    tree = yes;
    tropical = yes;
    clr = c;
    juice = j;
    sour = sr;
    eating = e;
}

void Apple::show() {
    cout << name << "りんご:\n";
    cout << "一年生植物:";    out( annual );
    cout << "多年生植物:";    out( perennial );
    cout << "木:";            out( tree );
    cout << "熱帯性:";        out( tropical );
    
    cout << "色:" << c[clr] << "\n";
    cout << "料理用";          out( cooking );
    cout << "かたい";          out( crunchy );
    cout << "食用";            out( eating );
    cout << "\n";
}

void Orange::show() {
    cout << name << "オレンジ:\n";
    cout << "一年生植物:";     out( annual );
    cout << "多年生植物:";     out( perennial );
    cout << "木:";             out( tree );
    cout << "熱帯性:";         out( tropical );

    cout << "色" << c[clr] << "\n";
    cout << "ジュース用:";     out( juice );
    cout << "酸っぱい:";       out( sour );
    cout << "食用:";           out( eating );
    cout << "\n";
}

void out( enum yn x ) {
    if ( x == no ) cout << "no\n";
    else cout << "yes\n";
}

int main() {
    Apple a1, a2;
    Orange o1, o2;

    a1.seta("レッドデリシャス", red, no, yes, yes );
    a2.seta("ジョナサン", red, yes, no, yes );

    o1.seto("ネーブル", orange, no, no, yes );
    o2.seto("バレンシア", orange, yes, yes, no);

    a1.show();
    a2.show();

    o1.show();
    o2.show();

    return 0;
}

コンパイル

$ g++ -o study54 study54.cpp

実行

レッドデリシャスりんご:
一年生植物:no
多年生植物:yes
木:yes
熱帯性:no
色:赤
料理用no
かたいyes
食用yes

ジョナサンりんご:
一年生植物:no
多年生植物:yes
木:yes
熱帯性:no
色:赤
料理用yes
かたいno
食用yes

ネーブルオレンジ:
一年生植物:no
多年生植物:yes
木:yes
熱帯性:yes
色オレンジ
ジュース用:no
酸っぱい:no
食用:yes

バレンシアオレンジ:
一年生植物:no
多年生植物:yes
木:yes
熱帯性:yes
色オレンジ
ジュース用:yes
酸っぱい:yes
食用:no

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】継承①

f:id:AtsuyaKoike:20190524095847p:plain:w300

  • 継承をすることで、最も汎用的なクラスから、最も特化されたクラスへの流れを示すクラス階層を作成できる。
  • あるクラスを別のクラスが継承するとき
    • 継承される側のクラスを 基本クラス と呼ぶ
    • 継承する側のクラスを 派生クラス と呼ぶ
#include <iostream>
using namespace std;

class B { 
    int i;
public:
    void set_i( int );
    int get_i();
};

class D : public B {
    int j;
public:
    void set_j( int );
    int mul();
};

void B::set_i( int n ) {
    i = n;
}

int B::get_i() {
    return i;
}

void D::set_j( int n ) {
    j = n;
}

int D::mul() {
    return j * get_i();
}

int main() {
    D ob;

    ob.set_i( 10 );
    ob.set_j( 4 );

    cout << ob.mul() << endl;

    return 0;
}
  • mul()に注目
    • 特にオブジェクトにリンクすることなく、Bクラスのメンバであるget_i()を呼び出している。
    • mul()では非公開メンバのiにアクセスできないため、get_i()関数を呼び出す。

コンパイル

$ g++ -o study52 study52.cpp

実行

$ ./study52 
40

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】仮引数を受け取るコンストラクタ

f:id:AtsuyaKoike:20190524095847p:plain:w300

  • コンストラクタ関数には引数を渡すことができる

study48.cpp

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

class strtype {
    char *p;
    int len;
public:
    strtype( char * );
    ~strtype();
    void show();
};

strtype::strtype( char *ptr ) {
    len = strlen( ptr );
    p = ( char *) malloc( len + 1 );
    if ( !p ) {
        cout << "メモリ割り当てエラー" << endl;
        exit(1);
    }
    strcpy( p, ptr );
}

strtype::~strtype() {
    cout << "pを開放する" << endl;
    free( p );
}

void strtype::show() {
    cout << p << " - 長さ:" << len << endl;
}

int main() {
    strtype s1("This is a test."), s2("I like C++.");
    s1.show();
    s2.show();

    return 0;
}

コンパイル

$ g++ -o study48 study48.cpp 

実行

$ ./study48 
This is a test. - 長さ:15
I like C++. - 長さ:11
pを開放する
pを開放する

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】コンストラクタ関数とデストラクタ関数

f:id:AtsuyaKoike:20190524095847p:plain:w300

  • コンストラクタ関数
    • クラス名と同じ。
    • スタックの索引値を設定することができる
    • オブジェクト作成時に実行される
  • デストラクタ関数
    • オブジェクトが破棄されるときに呼び出される
      • mainでオブジェクトが生成されていたとしたら、mainを抜けるとき
    • 例えばオブジェクト生成時にメモリを割り当てた場合は、メモリを開放する
    • コンストラクタ関数の名前の頭に「~」をつけたものがデストラクタ関数

study41.cpp

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

#define SIZE 255

class strtype {
    char *p;
    int len;
public:
    strtype();
    ~strtype();
    void set( char * );
    void show();
};

strtype::strtype() {
    p = ( char * ) malloc(SIZE);
    if ( !p ) {
        cout << "メモリ割り当てエラー" << endl;
        exit(1);
    }
    *p = '\0';
    len = 0;
}

strtype::~strtype() {
    cout << "pを開放する" << endl;
    free(p);
}

void strtype::set( char *ptr ) {
    if ( strlen( ptr ) >= SIZE ) {
        cout << "文字列が大きすぎる" << endl;
        return;
    }
    strcpy( p, ptr );
    len = strlen( p );
}

void strtype::show() {
    cout << p << " - 長さ:" << len << endl;
}

int main() {
    strtype s1, s2;
    s1.set( "This is a test." );
    s2.set( "I like C++." );
    s1.show();
    s2.show();

    return 0;
}

コンパイル

$ g++ -o study41 study41.cpp 

Warningがでますが、今回は気にしないということで。

実行

$ ./study41 
This is a test. - 長さ:15
I like C++. - 長さ:11
pを開放する
pを開放する

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】オーバーロード

f:id:AtsuyaKoike:20190524095847p:plain:w300

  • 関数オーバーロードの主な用途として、コンパイル時ポリフォーリズムを行うことが挙げられる
  • 1つの名前をオーバーロードすることで、複数あるデータの方の種類などに対応できる
    • 関数をたくさん作り、それぞれ別の名前をつける必要がない

study29.cpp

#include <iostream>
using namespace std;

int myabs( int );
long myabs( long );
double myabs( double );

int main() {
    cout << "-10の絶対値:" << myabs(-10) << endl << endl;
    cout << "-10Lの絶対値:" << myabs(-10L) << endl << endl;
    cout << "-10.01の絶対値:" << myabs(-10.01) << endl << endl;
}

int myabs( int n ) {
    cout << "整数用のmyabs()" << endl;
    return n<0 ? -n : n;
}

long myabs( long n ) {
    cout << "長整数用のmyabs()" << endl;
    return n<0 ? -n : n;
}

double myabs( double n ) {
    cout << "倍精度浮動小数点数用のmyabs()" << endl;
    return n<0 ? -n : n;
}

コンパイル

g++ -o study29 study29.cpp

実行

$ ./study29
整数用のmyabs()
-10の絶対値:10

長整数用のmyabs()
-10Lの絶対値:10

倍精度浮動小数点数用のmyabs()
-10.01の絶対値:10.01

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】クラスの作成

f:id:AtsuyaKoike:20190524095847p:plain:w300

概要

  • 1つのクラスに対して複数のオブジェクトを作ることができる。
  • 今回はstackクラスに対して、s1とs2という名前でオブジェクトを作成する。
  • オブジェクト同士は干渉しない

study21.cpp

#include <iostream>
using namespace std;

#define SIZE 10

// 文字列の保存
class stack {
    char stck[SIZE];
    int tos;
    public:
        void init();
        void push( char ch );
        char pop();
};

void stack::init() {
    tos = 0;
}
void stack::push( char ch ) {
    if ( tos == SIZE ) {
        cout << "スタックはいっぱいです";
        return;
    }
    stck[tos] = ch;
    tos++;
}

char stack::pop() {
    if ( tos == 0 ) {
        cout << "スタックは空です";
        return 0;
    }
    tos--;
    return stck[tos];
}

int main() {
    stack s1, s2;
    int i;

    s1.init();
    s2.init();
    s1.push('a');
    s2.push('x');
    s1.push('b');
    s2.push('y');
    s1.push('c');
    s2.push('z');

    for ( i=0; i<3; i++ ) cout << "s1をポップする:" << s1.pop() << endl;
    for ( i=0; i<3; i++ ) cout << "s2をポップする:" << s2.pop() << endl;

    return 0;
}

コンパイル

g++ -o study21 study21.cpp 

実行

s1をポップする:c
s1をポップする:b
s1をポップする:a
s2をポップする:z
s2をポップする:y
s2をポップする:x

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768