1 Востаннє редагувалося Betterthanyou (20.02.2018 00:28:15)

Тема: Чому функція абстрактного класу не може бути тільки для читання

struct Abstract {
    virtual std::string getClassName() = 0; // pure virtual
    void show() const
    {
        std::cout << "Abstract = " <<this->getClassName() <<  '\n';
    };
};

struct a : Abstract {
    virtual std::string getClassName() override
    {
        return "a";
    }
};

struct b : Abstract {
    virtual std::string getClassName() override
    {
        return "b";
    }
};

int main() 
{
    a obj;
    obj.show();
    return 0;
}

Чому функція абстрактного класу не може бути тільки для читання ? Якщо писати "const" тоді виникає помилка
error: passing ‘const Abstract’ as ‘this’ argument of ‘virtual std::string Abstract::getClassName()’ discards qualifiers [-fpermissive]
Метод show не модифікує об'єкт, а лише бере дані.

Прихований текст

Я знаю що для вирішення проблеми потрібно забрати "const" з show функції, моє питання: чому так відбувається ?

Подякували: leofun011

2

Re: Чому функція абстрактного класу не може бути тільки для читання

ви викликаєте неконстантний гетер у константному методі

Подякували: koala, leofun01, Betterthanyou, Yola, varkon, LoganRoss6

3

Re: Чому функція абстрактного класу не може бути тільки для читання

Давайте одразу скажемо, що

void f(X x); // і
void f(const X x);


це дві різні функції. Принципово різні. Настільки, що вони можуть існувати одночасно і не заважати одна одній. Якщо ви пишете для неконстантного t f(t) і існує лише f(const), буде викликано перетворення на const (тотожне), а потім f(const). Але навпаки (з const на не-const) перетворення можливе лише явне, за допомогою const_cast.
Крім того, не існує "константних функцій". Модифікатор методу const застосовується до параметру this.
А тепер дивіться, що ви робите:

struct Abstract {
    virtual std::string getClassName() = 0; // pure virtual для _неконстантного_ this
    void show() const
    {
        std::cout << "Abstract = " <<this->getClassName() <<  '\n'; //WTF, ми не вміємо робити show для const this!
    };
};

Додайте const до всіх getClassName - і буде вам щастя.

Подякували: sensei, leofun01, Betterthanyou3

4

Re: Чому функція абстрактного класу не може бути тільки для читання

#include <iostream>
#include <string>

struct Abstract {
    virtual std::string getClassName() const = 0; // pure virtual
    void show() const
    {
        std::cout << "Abstract = " << this->getClassName() <<  '\n';
    };
};

struct a : Abstract {
    virtual std::string getClassName() const override
    {
        return "a";
    }
};

struct b : Abstract {
    virtual std::string getClassName() const override
    {
        return "b";
    }
};

int main() 
{
    a obj;
    obj.show();
    return 0;
}
Подякували: Betterthanyou1

5 Востаннє редагувалося Yola (20.02.2018 09:46:47)

Re: Чому функція абстрактного класу не може бути тільки для читання

koala написав:
void f(X x); // і
void f(const X x);


це дві різні функції. Принципово різні. Настільки, що вони можуть існувати одночасно і не заважати одна одній.

Ого! Це типу одрук чи як? Можна найменший-перевірний-приклад?

компілятор написав:

яке мені діло const там чи не const, якщо я все одно туди копіюватиму?

Подякували: Betterthanyou, sensei, leofun013

6

Re: Чому функція абстрактного класу не може бути тільки для читання

Так, наплутав увечері. Це дійсно для посилань, а не для значень: https://ideone.com/NtOgR6
Треба раніше лягати спати...

Подякували: Yola, Betterthanyou, leofun013

7

Re: Чому функція абстрактного класу не може бути тільки для читання

Можна вставити не константне значення у виклик функції з нетиповими параметрами шаблонів?
наприклад bitset

int b;
std::cin>>b;
std::bitset<b>(0b1100);

(Я вже пробував використовувати явні конвертації - не допомагають, помилка error: the value of ‘b’ is not usable in a constant expression)

8

Re: Чому функція абстрактного класу не може бути тільки для читання

Betterthanyou написав:
int b;
std::cin>>b;
std::bitset<b>(0b1100);

ні, так не можна.

std::bitset<5> і std::bitset<6> - це різні типи, хоча вони й можуть використовувати один і той самий код.

Подякували: Betterthanyou1

9

Re: Чому функція абстрактного класу не може бути тільки для читання

Betterthanyou написав:

Можна вставити не константне значення у виклик функції з нетиповими параметрами шаблонів?
наприклад bitset

int b;
std::cin>>b;
std::bitset<b>(0b1100);

(Я вже пробував використовувати явні конвертації - не допомагають, помилка error: the value of ‘b’ is not usable in a constant expression)

По тій же причині, що ви не можете написати так:

int a;
cin >> a;
int arr[a];
Прихований текст

http://www.cplusplus.com/reference/bitset/bitset/
The size of a bitset is fixed at compile-time (determined by its template parameter).

10 Востаннє редагувалося Betterthanyou (20.02.2018 15:23:35)

Re: Чому функція абстрактного класу не може бути тільки для читання

sensei написав:
int a;
cin >> a;
int arr[a];

Так я можу написати
https://msdn.microsoft.com/en-us/library/zb1574zs.aspx

Подякували: koala1

11 Востаннє редагувалося Yola (20.02.2018 15:34:04)

Re: Чому функція абстрактного класу не може бути тільки для читання

Betterthanyou написав:
sensei написав:
int a;
cin >> a;
int arr[a];

Так я можу написати
https://msdn.microsoft.com/en-us/library/zb1574zs.aspx

Дійсно нема причин окрім бажання/небажання постачальників компліторів, щоб втілити масиви розмір яких визначається під час виконання. gcc дозволяє такі масиви. Але це інше ніж відмінні типи.

З масивами це всього лише скільки пам'яті виділити на стеку. І це можна визначати кожен раз при виклику функції в якій цей масив оголошено.

З типами інакше, щоб використовувати тип потрібно знати адреси всіх його функцій, і це треба знати під час компіляції. І взагалі, чи ця функція у типа є, бо bitset<5> і bitset<6> можуть мати різні набори членів.

Подякували: Betterthanyou, leofun012

12

Re: Чому функція абстрактного класу не може бути тільки для читання

Betterthanyou написав:

Так я можу написати
https://msdn.microsoft.com/en-us/library/zb1574zs.aspx

Звичайно можете, тільки раз ви послуговуєтесь с++ ним бітсетом, то і не вмішуйте сюди сішний стандарт,
а с++11 стандарті масив ініціалізується constant-expression'ом


Yola написав:

Дійсно нема причин окрім бажання/небажання постачальників компліторів, щоб втілити масиви розмір яких визначається під час виконання. gcc дозволяє такі масиви. Але це інше ніж відмінні типи.

З масивами це всього лише скільки пам'яті виділити на стеку. І це можна визначати кожен раз при виклику функції в якій цей масив оголошено.

З типами інакше, щоб використовувати тип потрібно знати адреси всіх його функцій, і це треба знати під час компіляції. І взагалі, чи ця функція у типа є, бо bitset<5> і bitset<6> можуть мати різні набори членів.

Я розумію, я хотів донести інше, що як з шаблонами так і з масивами - їх тип\розмір повинен бути відомим на етапі компіляції, тому просту змінну туди і не засунути

Подякували: Betterthanyou1

13 Востаннє редагувалося ReAl (20.02.2018 16:28:27)

Re: Чому функція абстрактного класу не може бути тільки для читання

Yola написав:

Дійсно нема причин окрім бажання/небажання постачальників компліторів, щоб втілити масиви розмір яких визначається під час виконання. gcc дозволяє такі масиви. Але це інше ніж відмінні типи.

Дозволяє стандарт C99 (VLA, variable length array).
Просто доволі довго gcc був єдиним компілятором, який їсть таке:

#include <stdio.h>

#define PRS(a) printf( "\tsizeof(" #a ") = %d\n", sizeof(a))

void func(int x, int y, int arr[y][x])
{
        int locarr[y][x];
        printf("x= %d, y=%d\n", x, y);
        PRS(locarr);    // Тут розмір масиву
        PRS(arr);        // Тут розмір _вказівника_
        PRS(arr[0]);
        PRS(arr[0][0]);
}

int main()
{
        int a1[3][6];
        int a2[4][2];
        func(6, 3, a1);
        func(2, 4, a2);
        return 0;
}

$ gcc -O2 -s --std=c99 --pedantic -o t99 t99.c
$ ./t99
x= 6, y=3
    sizeof(locarr) = 72
    sizeof(arr) = 4
    sizeof(arr[0]) = 24
    sizeof(arr[0][0]) = 4
x= 2, y=4
    sizeof(locarr) = 32
    sizeof(arr) = 4
    sizeof(arr[0]) = 8
    sizeof(arr[0][0]) = 4

Подякували: Betterthanyou, leofun01, Yola3

14 Востаннє редагувалося Betterthanyou (20.02.2018 16:52:05)

Re: Чому функція абстрактного класу не може бути тільки для читання

не по темі
sensei написав:

Звичайно можете, тільки раз ви послуговуєтесь с++ ним бітсетом, то і не вмішуйте сюди сішний стандарт,
а с++11 стандарті масив ініціалізується constant-expression'ом

Так в С++ використовується std::array, хіба ні ? Те що ви написали це С стиль.

15

Re: Чому функція абстрактного класу не може бути тільки для читання

Betterthanyou написав:

Так в С++ використовується std::array, хіба ні ? Те що ви написали це С стиль.

C стиль, який успішно перекочував в С++
до речі ось і сам стандарт, де на 179 сторінці 8.3.4 йдеться про оголошення масивів

а std::array це бібліотечна обгортка над звичайними масивами

Подякували: Betterthanyou, leofun012